From c63ecf908a784ae0e7ab43e3d904f139d45b4d6b Mon Sep 17 00:00:00 2001 From: Kevin Davis Date: Mon, 18 Jan 2021 12:12:37 -0700 Subject: [PATCH] Cdp accumulators (#751) * Add 'InterestFactor' to CDP type (#734) * update cdp type to include interest factor * fix build * Add cdp accumulator methods (#735) * remame fees to interest * add accumulate interest method * add basic test * add note * address review comments * update tests * Add sync cdp interest method (#737) * remame fees to interest * add accumulate interest method * add basic test * add note * address review comments * update tests * remove old fee functions * add method to synchronize cdp interest * add multi-cdp tests * add test with many blocks * add test for interest getter * address review comments * calculate time difference then convert to seconds * fix: update collateral index when syncing interest * fix: differentiate between case when apy is zero and all fees are being rounded to zero * fix: round time difference properly * update cdp genesis state and migrations (#738) * remame fees to interest * add accumulate interest method * add basic test * add note * address review comments * update tests * remove old fee functions * add method to synchronize cdp interest * add multi-cdp tests * add test with many blocks * add test for interest getter * update cdp genesis state and migrations * address review comments * calculate time difference then convert to seconds * fix: update collateral index when syncing interest * fix: differentiate between case when apy is zero and all fees are being rounded to zero * fix: simplify add/remove/update collateral index * update genesis state to include total principal amounts * update migration * Delete kava-4-cdp-state-block-500000.json * Add cdp liquidations by external keeper (#750) * feat: split liquidations between external keepers and automated begin blocker * address review comments * USDX incentive accumulators (#752) * feat: split liquidations between external keepers and automated begin blocker * wip: refactor usdx minting incentives to use accumulators/hooks * wip: refactor usdx minting claim object * feat: use accumulators/hooks for usdx minting rewards * fix: get tests passing * fix: don't create claim objects unless that cdp type is eligable for rewards * add begin blocker * update client * cleanup comments/tests * update querier * address review comments * fix: check for division by zero * address review comments * run hook before interest is synced * Remove savings rate (#764) * remove savings rate * remove savings rate from debt param * update migrations * address review comments * Add usdx incentives calculation test (#765) * add usdx incentive calculation test * update reward calculation * add allowable error to test criteria * Update x/incentive/keeper/rewards_test.go Co-authored-by: Kevin Davis * fix: remove old fields from test genesis state Co-authored-by: Ruaridh Co-authored-by: Ruaridh --- app/app.go | 7 +- migrate/v0_11/migrate.go | 60 +- migrate/v0_11/migrate_test.go | 25 - migrate/v0_13/migrate.go | 69 + migrate/v0_13/migrate_test.go | 43 + .../kava-4-cdp-state-block-500000.json | 29102 ++++++++++++++++ x/auction/types/auctions.go | 5 +- x/cdp/abci.go | 25 +- x/cdp/abci_test.go | 2 +- x/cdp/alias.go | 127 +- x/cdp/client/cli/query.go | 56 - x/cdp/client/cli/tx.go | 32 + x/cdp/client/rest/query.go | 38 - x/cdp/client/rest/rest.go | 7 + x/cdp/client/rest/tx.go | 33 + x/cdp/genesis.go | 41 +- x/cdp/genesis_test.go | 88 +- x/cdp/handler.go | 18 + x/cdp/integration_test.go | 137 +- x/cdp/keeper/cdp.go | 74 +- x/cdp/keeper/cdp_test.go | 12 +- x/cdp/keeper/deposit.go | 43 +- x/cdp/keeper/draw.go | 25 +- x/cdp/keeper/draw_test.go | 31 - x/cdp/keeper/fees.go | 137 - x/cdp/keeper/fees_test.go | 101 - x/cdp/keeper/hooks.go | 23 + x/cdp/keeper/integration_test.go | 263 +- x/cdp/keeper/interest.go | 164 + x/cdp/keeper/interest_test.go | 763 + x/cdp/keeper/keeper.go | 123 +- x/cdp/keeper/keeper_test.go | 12 - x/cdp/keeper/querier.go | 38 - x/cdp/keeper/querier_test.go | 14 +- x/cdp/keeper/savings.go | 106 - x/cdp/keeper/savings_test.go | 113 - x/cdp/keeper/seize.go | 70 + x/cdp/keeper/seize_test.go | 253 + x/cdp/legacy/v0_11/types.go | 75 +- x/cdp/legacy/v0_13/types.go | 653 + x/cdp/legacy/v0_9/types.go | 38 + x/cdp/simulation/decoder.go | 7 - x/cdp/simulation/decoder_test.go | 4 +- x/cdp/simulation/genesis.go | 42 +- x/cdp/simulation/operations.go | 8 +- x/cdp/spec/02_state.md | 2 + x/cdp/types/cdp.go | 18 +- x/cdp/types/cdp_test.go | 14 +- x/cdp/types/errors.go | 6 + x/cdp/types/expected_keepers.go | 6 + x/cdp/types/genesis.go | 117 +- x/cdp/types/hooks.go | 25 + x/cdp/types/keys.go | 25 +- x/cdp/types/msg.go | 56 + x/cdp/types/params.go | 191 +- x/cdp/types/params_test.go | 624 +- x/committee/keeper/param_permission_test.go | 1 - x/committee/legacy/v0_11/types.go | 2 +- x/committee/legacy/v0_9/types.go | 2 +- x/committee/types/param_permissions_test.go | 13 +- x/committee/types/permissions.go | 4 +- x/hard/legacy/{v0_12 => v0_11}/types.go | 72 +- x/incentive/abci.go | 9 +- x/incentive/alias.go | 105 +- x/incentive/client/cli/query.go | 96 +- x/incentive/client/cli/tx.go | 8 +- x/incentive/client/rest/query.go | 68 +- x/incentive/client/rest/tx.go | 2 +- x/incentive/genesis.go | 56 +- x/incentive/handler.go | 30 +- x/incentive/handler_test.go | 29 +- x/incentive/keeper/hooks.go | 28 + x/incentive/keeper/integration_test.go | 212 + x/incentive/keeper/keeper.go | 222 +- x/incentive/keeper/keeper_test.go | 161 +- x/incentive/keeper/params.go | 30 + x/incentive/keeper/payout.go | 103 +- x/incentive/keeper/payout_test.go | 533 +- x/incentive/keeper/querier.go | 50 +- x/incentive/keeper/querier_test.go | 48 - x/incentive/keeper/rewards.go | 250 +- x/incentive/keeper/rewards_test.go | 501 +- x/incentive/simulation/decoder.go | 36 +- x/incentive/simulation/decoder_test.go | 20 +- x/incentive/simulation/genesis.go | 112 +- x/incentive/simulation/operations.go | 101 +- x/incentive/simulation/params.go | 16 +- x/incentive/types/claims.go | 112 + x/incentive/types/claims_test.go | 66 + x/incentive/types/codec.go | 6 +- x/incentive/types/errors.go | 3 +- x/incentive/types/expected_keepers.go | 9 +- x/incentive/types/genesis.go | 127 +- x/incentive/types/genesis_test.go | 241 +- x/incentive/types/keys.go | 44 +- x/incentive/types/msg.go | 28 +- x/incentive/types/msg_test.go | 14 +- x/incentive/types/params.go | 184 +- x/incentive/types/params_test.go | 238 +- x/incentive/types/querier.go | 13 +- x/incentive/types/rewards.go | 281 - x/incentive/types/rewards_test.go | 282 - 102 files changed, 34415 insertions(+), 4344 deletions(-) create mode 100644 migrate/v0_13/migrate.go create mode 100644 migrate/v0_13/migrate_test.go create mode 100644 migrate/v0_13/testdata/kava-4-cdp-state-block-500000.json delete mode 100644 x/cdp/keeper/fees.go delete mode 100644 x/cdp/keeper/fees_test.go create mode 100644 x/cdp/keeper/hooks.go create mode 100644 x/cdp/keeper/interest.go create mode 100644 x/cdp/keeper/interest_test.go delete mode 100644 x/cdp/keeper/savings.go delete mode 100644 x/cdp/keeper/savings_test.go create mode 100644 x/cdp/legacy/v0_13/types.go create mode 100644 x/cdp/types/hooks.go rename x/hard/legacy/{v0_12 => v0_11}/types.go (82%) create mode 100644 x/incentive/keeper/hooks.go create mode 100644 x/incentive/keeper/integration_test.go delete mode 100644 x/incentive/keeper/querier_test.go create mode 100644 x/incentive/types/claims.go create mode 100644 x/incentive/types/claims_test.go delete mode 100644 x/incentive/types/rewards.go delete mode 100644 x/incentive/types/rewards_test.go diff --git a/app/app.go b/app/app.go index cf25dbec..1ba20a3b 100644 --- a/app/app.go +++ b/app/app.go @@ -99,7 +99,6 @@ var ( auction.ModuleName: nil, cdp.ModuleName: {supply.Minter, supply.Burner}, cdp.LiquidatorMacc: {supply.Minter, supply.Burner}, - cdp.SavingsRateMacc: {supply.Minter}, bep3.ModuleName: {supply.Minter, supply.Burner}, kavadist.ModuleName: {supply.Minter}, issuance.ModuleAccountName: {supply.Minter, supply.Burner}, @@ -341,7 +340,7 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts AppOptio app.supplyKeeper, auctionSubspace, ) - app.cdpKeeper = cdp.NewKeeper( + cdpKeeper := cdp.NewKeeper( app.cdc, keys[cdp.StoreKey], cdpSubspace, @@ -370,7 +369,7 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts AppOptio keys[incentive.StoreKey], incentiveSubspace, app.supplyKeeper, - app.cdpKeeper, + &cdpKeeper, app.accountKeeper, ) app.issuanceKeeper = issuance.NewKeeper( @@ -396,6 +395,8 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts AppOptio app.stakingKeeper = *stakingKeeper.SetHooks( staking.NewMultiStakingHooks(app.distrKeeper.Hooks(), app.slashingKeeper.Hooks())) + app.cdpKeeper = *cdpKeeper.SetHooks(cdp.NewMultiCDPHooks(app.incentiveKeeper.Hooks())) + // create the module manager (Note: Any module instantiated in the module manager that is later modified // must be passed by reference here.) app.mm = module.NewManager( diff --git a/migrate/v0_11/migrate.go b/migrate/v0_11/migrate.go index b0250962..7000a3c8 100644 --- a/migrate/v0_11/migrate.go +++ b/migrate/v0_11/migrate.go @@ -22,12 +22,12 @@ import ( v38_5supply "github.com/kava-labs/kava/migrate/v0_11/legacy/cosmos-sdk/v0.38.5/supply" v0_11bep3 "github.com/kava-labs/kava/x/bep3" v0_9bep3 "github.com/kava-labs/kava/x/bep3/legacy/v0_9" - v0_11cdp "github.com/kava-labs/kava/x/cdp" + v0_11cdp "github.com/kava-labs/kava/x/cdp/legacy/v0_11" v0_9cdp "github.com/kava-labs/kava/x/cdp/legacy/v0_9" v0_11committee "github.com/kava-labs/kava/x/committee" v0_9committee "github.com/kava-labs/kava/x/committee/legacy/v0_9" - v0_11harvest "github.com/kava-labs/kava/x/hard" - v0_11incentive "github.com/kava-labs/kava/x/incentive" + v0_11harvest "github.com/kava-labs/kava/x/hard/legacy/v0_11" + v0_11incentive "github.com/kava-labs/kava/x/incentive/legacy/v0_11" v0_9incentive "github.com/kava-labs/kava/x/incentive/legacy/v0_9" v0_11issuance "github.com/kava-labs/kava/x/issuance" v0_11pricefeed "github.com/kava-labs/kava/x/pricefeed" @@ -129,7 +129,7 @@ func MigrateAppState(v0_9AppState v39_genutil.AppMap) v39_genutil.AppMap { delete(v0_9AppState, v0_9pricefeed.ModuleName) v0_11AppState[v0_9pricefeed.ModuleName] = v0_11Codec.MustMarshalJSON(MigratePricefeed(pricefeedGenState)) } - // v0_11AppState[v0_11harvest.ModuleName] = v0_11Codec.MustMarshalJSON(MigrateHarvest()) + v0_11AppState[v0_11harvest.ModuleName] = v0_11Codec.MustMarshalJSON(MigrateHarvest()) v0_11AppState[v0_11issuance.ModuleName] = v0_11Codec.MustMarshalJSON(v0_11issuance.DefaultGenesisState()) return v0_11AppState } @@ -308,7 +308,6 @@ func MigrateCommittee(oldGenState v0_9committee.GenesisState) v0_11committee.Gen DebtFloor: oldDebtParam.DebtFloor, Denom: oldDebtParam.Denom, ReferenceAsset: oldDebtParam.ReferenceAsset, - SavingsRate: oldDebtParam.SavingsRate, } oldAssetParam := subPermission.AllowedAssetParams[0] newAssetParam := v0_11committee.AllowedAssetParam{ @@ -633,34 +632,29 @@ func MigrateGov(oldGenState v39_1gov.GenesisState) v39_1gov.GenesisState { return oldGenState } -// // MigrateHarvest initializes the harvest genesis state for kava-4 -// func MigrateHarvest() v0_11harvest.GenesisState { -// // total HARD per second for lps (week one): 633761 -// // HARD per second for delegators (week one): 1267522 -// incentiveGoLiveDate := time.Date(2020, 10, 16, 14, 0, 0, 0, time.UTC) -// incentiveEndDate := time.Date(2024, 10, 16, 14, 0, 0, 0, time.UTC) -// claimEndDate := time.Date(2025, 10, 16, 14, 0, 0, 0, time.UTC) -// harvestGS := v0_11harvest.NewGenesisState(v0_11harvest.NewParams( -// true, -// v0_11harvest.DistributionSchedules{ -// v0_11harvest.NewDistributionSchedule(true, "usdx", incentiveGoLiveDate, incentiveEndDate, sdk.NewCoin("hard", sdk.NewInt(310543)), claimEndDate, v0_11harvest.Multipliers{v0_11harvest.NewMultiplier(v0_11harvest.Small, 1, sdk.MustNewDecFromStr("0.33")), v0_11harvest.NewMultiplier(v0_11harvest.Large, 12, sdk.OneDec())}), -// v0_11harvest.NewDistributionSchedule(true, "hard", incentiveGoLiveDate, incentiveEndDate, sdk.NewCoin("hard", sdk.NewInt(285193)), claimEndDate, v0_11harvest.Multipliers{v0_11harvest.NewMultiplier(v0_11harvest.Small, 1, sdk.MustNewDecFromStr("0.33")), v0_11harvest.NewMultiplier(v0_11harvest.Large, 12, sdk.OneDec())}), -// v0_11harvest.NewDistributionSchedule(true, "bnb", incentiveGoLiveDate, incentiveEndDate, sdk.NewCoin("hard", sdk.NewInt(12675)), claimEndDate, v0_11harvest.Multipliers{v0_11harvest.NewMultiplier(v0_11harvest.Small, 1, sdk.MustNewDecFromStr("0.33")), v0_11harvest.NewMultiplier(v0_11harvest.Large, 12, sdk.OneDec())}), -// v0_11harvest.NewDistributionSchedule(true, "ukava", incentiveGoLiveDate, incentiveEndDate, sdk.NewCoin("hard", sdk.NewInt(25350)), claimEndDate, v0_11harvest.Multipliers{v0_11harvest.NewMultiplier(v0_11harvest.Small, 1, sdk.MustNewDecFromStr("0.33")), v0_11harvest.NewMultiplier(v0_11harvest.Large, 12, sdk.OneDec())}), -// }, -// v0_11harvest.DelegatorDistributionSchedules{v0_11harvest.NewDelegatorDistributionSchedule( -// v0_11harvest.NewDistributionSchedule(true, "ukava", incentiveGoLiveDate, incentiveEndDate, sdk.NewCoin("hard", sdk.NewInt(1267522)), claimEndDate, v0_11harvest.Multipliers{v0_11harvest.NewMultiplier(v0_11harvest.Small, 1, sdk.MustNewDecFromStr("0.33")), v0_11harvest.NewMultiplier(v0_11harvest.Large, 12, sdk.OneDec())}), -// time.Hour*24, -// ), -// }, -// v0_11harvest.BlockLimits{ -// v0_11harvest.NewBlockLimit("usdx", sdk.Dec(0.9)), -// v0_11harvest.NewBlockLimit("ukava", sdk.Dec(0.6)), -// v0_11harvest.NewBlockLimit("bnb", sdk.Dec(0.9)), -// }, -// ), v0_11harvest.DefaultPreviousBlockTime, v0_11harvest.DefaultDistributionTimes) -// return harvestGS -// } +// MigrateHarvest initializes the harvest genesis state for kava-4 +func MigrateHarvest() v0_11harvest.GenesisState { + // total HARD per second for lps (week one): 633761 + // HARD per second for delegators (week one): 1267522 + incentiveGoLiveDate := time.Date(2020, 10, 16, 14, 0, 0, 0, time.UTC) + incentiveEndDate := time.Date(2024, 10, 16, 14, 0, 0, 0, time.UTC) + claimEndDate := time.Date(2025, 10, 16, 14, 0, 0, 0, time.UTC) + harvestGS := v0_11harvest.NewGenesisState(v0_11harvest.NewParams( + true, + v0_11harvest.DistributionSchedules{ + v0_11harvest.NewDistributionSchedule(true, "usdx", incentiveGoLiveDate, incentiveEndDate, sdk.NewCoin("hard", sdk.NewInt(310543)), claimEndDate, v0_11harvest.Multipliers{v0_11harvest.NewMultiplier(v0_11harvest.Small, 1, sdk.MustNewDecFromStr("0.33")), v0_11harvest.NewMultiplier(v0_11harvest.Large, 12, sdk.OneDec())}), + v0_11harvest.NewDistributionSchedule(true, "hard", incentiveGoLiveDate, incentiveEndDate, sdk.NewCoin("hard", sdk.NewInt(285193)), claimEndDate, v0_11harvest.Multipliers{v0_11harvest.NewMultiplier(v0_11harvest.Small, 1, sdk.MustNewDecFromStr("0.33")), v0_11harvest.NewMultiplier(v0_11harvest.Large, 12, sdk.OneDec())}), + v0_11harvest.NewDistributionSchedule(true, "bnb", incentiveGoLiveDate, incentiveEndDate, sdk.NewCoin("hard", sdk.NewInt(12675)), claimEndDate, v0_11harvest.Multipliers{v0_11harvest.NewMultiplier(v0_11harvest.Small, 1, sdk.MustNewDecFromStr("0.33")), v0_11harvest.NewMultiplier(v0_11harvest.Large, 12, sdk.OneDec())}), + v0_11harvest.NewDistributionSchedule(true, "ukava", incentiveGoLiveDate, incentiveEndDate, sdk.NewCoin("hard", sdk.NewInt(25350)), claimEndDate, v0_11harvest.Multipliers{v0_11harvest.NewMultiplier(v0_11harvest.Small, 1, sdk.MustNewDecFromStr("0.33")), v0_11harvest.NewMultiplier(v0_11harvest.Large, 12, sdk.OneDec())}), + }, + v0_11harvest.DelegatorDistributionSchedules{v0_11harvest.NewDelegatorDistributionSchedule( + v0_11harvest.NewDistributionSchedule(true, "ukava", incentiveGoLiveDate, incentiveEndDate, sdk.NewCoin("hard", sdk.NewInt(1267522)), claimEndDate, v0_11harvest.Multipliers{v0_11harvest.NewMultiplier(v0_11harvest.Small, 1, sdk.MustNewDecFromStr("0.33")), v0_11harvest.NewMultiplier(v0_11harvest.Large, 12, sdk.OneDec())}), + time.Hour*24, + ), + }, + ), v0_11harvest.DefaultPreviousBlockTime, v0_11harvest.DefaultDistributionTimes) + return harvestGS +} // MigrateCDP migrates from a v0.9 (or v0.10) cdp genesis state to a v0.11 cdp genesis state func MigrateCDP(oldGenState v0_9cdp.GenesisState) v0_11cdp.GenesisState { diff --git a/migrate/v0_11/migrate_test.go b/migrate/v0_11/migrate_test.go index 59d5a121..91501a9a 100644 --- a/migrate/v0_11/migrate_test.go +++ b/migrate/v0_11/migrate_test.go @@ -12,11 +12,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" v39_1auth "github.com/cosmos/cosmos-sdk/x/auth" v39_1auth_vesting "github.com/cosmos/cosmos-sdk/x/auth/vesting" - "github.com/cosmos/cosmos-sdk/x/genutil" v39_1supply "github.com/cosmos/cosmos-sdk/x/supply" - tmtypes "github.com/tendermint/tendermint/types" - "github.com/kava-labs/kava/app" v38_5auth "github.com/kava-labs/kava/migrate/v0_11/legacy/cosmos-sdk/v0.38.5/auth" v38_5supply "github.com/kava-labs/kava/migrate/v0_11/legacy/cosmos-sdk/v0.38.5/supply" @@ -167,25 +164,3 @@ func TestMigratePricefeed(t *testing.T) { err = newGenState.Validate() require.NoError(t, err) } - -func TestMigrateFull(t *testing.T) { - oldGenDoc, err := tmtypes.GenesisDocFromFile(filepath.Join("testdata", "kava-3-export.json")) - require.NoError(t, err) - - // 2) migrate - newGenDoc := Migrate(*oldGenDoc) - tApp := app.NewTestApp() - cdc := app.MakeCodec() - var newAppState genutil.AppMap - require.NoError(t, - cdc.UnmarshalJSON(newGenDoc.AppState, &newAppState), - ) - err = app.ModuleBasics.ValidateGenesis(newAppState) - if err != nil { - require.NoError(t, err) - } - require.NotPanics(t, func() { - // this runs both InitGenesis for all modules (which panic on errors) and runs all invariants - tApp.InitializeFromGenesisStatesWithTime(newGenDoc.GenesisTime, app.GenesisState(newAppState)) - }) -} diff --git a/migrate/v0_13/migrate.go b/migrate/v0_13/migrate.go new file mode 100644 index 00000000..aa265d93 --- /dev/null +++ b/migrate/v0_13/migrate.go @@ -0,0 +1,69 @@ +package v0_13 + +import ( + "time" + + v0_11cdp "github.com/kava-labs/kava/x/cdp/legacy/v0_11" + v0_13cdp "github.com/kava-labs/kava/x/cdp/legacy/v0_13" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// MigrateCDP migrates from a v0.9 (or v0.10) cdp genesis state to a v0.11 cdp genesis state +func MigrateCDP(oldGenState v0_11cdp.GenesisState) v0_13cdp.GenesisState { + var newCDPs v0_13cdp.CDPs + var newDeposits v0_13cdp.Deposits + var newCollateralParams v0_13cdp.CollateralParams + var newGenesisAccumulationTimes v0_13cdp.GenesisAccumulationTimes + var previousAccumulationTime time.Time + var totalPrincipals v0_13cdp.GenesisTotalPrincipals + newStartingID := oldGenState.StartingCdpID + + totalPrincipalMap := make(map[string]sdk.Int) + for _, cp := range oldGenState.Params.CollateralParams { + newCollateralParam := v0_13cdp.NewCollateralParam(cp.Denom, cp.Type, cp.LiquidationRatio, cp.DebtLimit, cp.StabilityFee, cp.AuctionSize, cp.LiquidationPenalty, cp.Prefix, cp.SpotMarketID, cp.LiquidationMarketID, sdk.MustNewDecFromStr("0.01"), sdk.NewInt(10), cp.ConversionFactor) + newCollateralParams = append(newCollateralParams, newCollateralParam) + newGenesisAccumulationTime := v0_13cdp.NewGenesisAccumulationTime(cp.Type, previousAccumulationTime, sdk.OneDec()) + newGenesisAccumulationTimes = append(newGenesisAccumulationTimes, newGenesisAccumulationTime) + totalPrincipalMap[cp.Type] = sdk.ZeroInt() + } + + for _, cdp := range oldGenState.CDPs { + newCDP := v0_13cdp.NewCDPWithFees(cdp.ID, cdp.Owner, cdp.Collateral, cdp.Type, cdp.Principal, cdp.AccumulatedFees, cdp.FeesUpdated, sdk.OneDec()) + if previousAccumulationTime.Before(cdp.FeesUpdated) { + previousAccumulationTime = cdp.FeesUpdated + } + totalPrincipalMap[cdp.Type] = totalPrincipalMap[cdp.Type].Add(newCDP.GetTotalPrincipal().Amount) + + newCDPs = append(newCDPs, newCDP) + } + + for _, dep := range oldGenState.Deposits { + newDep := v0_13cdp.NewDeposit(dep.CdpID, dep.Depositor, dep.Amount) + newDeposits = append(newDeposits, newDep) + } + + for ctype, tp := range totalPrincipalMap { + totalPrincipal := v0_13cdp.NewGenesisTotalPrincipal(ctype, tp) + totalPrincipals = append(totalPrincipals, totalPrincipal) + } + + oldDebtParam := oldGenState.Params.DebtParam + + newDebtParam := v0_13cdp.NewDebtParam(oldDebtParam.Denom, oldDebtParam.ReferenceAsset, oldDebtParam.ConversionFactor, oldDebtParam.DebtFloor) + + newGlobalDebtLimit := oldGenState.Params.GlobalDebtLimit + + newParams := v0_13cdp.NewParams(newGlobalDebtLimit, newCollateralParams, newDebtParam, oldGenState.Params.SurplusAuctionThreshold, oldGenState.Params.SurplusAuctionLot, oldGenState.Params.DebtAuctionThreshold, oldGenState.Params.DebtAuctionLot, false) + + return v0_13cdp.NewGenesisState( + newParams, + newCDPs, + newDeposits, + newStartingID, + oldGenState.DebtDenom, + oldGenState.GovDenom, + newGenesisAccumulationTimes, + totalPrincipals, + ) +} diff --git a/migrate/v0_13/migrate_test.go b/migrate/v0_13/migrate_test.go new file mode 100644 index 00000000..875b21c9 --- /dev/null +++ b/migrate/v0_13/migrate_test.go @@ -0,0 +1,43 @@ +package v0_13 + +import ( + "io/ioutil" + "os" + "path/filepath" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/kava-labs/kava/app" + v0_11cdp "github.com/kava-labs/kava/x/cdp/legacy/v0_11" + + "github.com/stretchr/testify/require" +) + +func TestMain(m *testing.M) { + config := sdk.GetConfig() + app.SetBech32AddressPrefixes(config) + app.SetBip44CoinType(config) + + os.Exit(m.Run()) +} + +func TestMigrateCdp(t *testing.T) { + bz, err := ioutil.ReadFile(filepath.Join("testdata", "kava-4-cdp-state-block-500000.json")) + require.NoError(t, err) + var oldGenState v0_11cdp.GenesisState + cdc := app.MakeCodec() + require.NotPanics(t, func() { + cdc.MustUnmarshalJSON(bz, &oldGenState) + }) + + newGenState := MigrateCDP(oldGenState) + err = newGenState.Validate() + require.NoError(t, err) + + require.Equal(t, len(newGenState.Params.CollateralParams), len(newGenState.PreviousAccumulationTimes)) + + cdp1 := newGenState.CDPs[0] + require.Equal(t, sdk.OneDec(), cdp1.InterestFactor) + +} diff --git a/migrate/v0_13/testdata/kava-4-cdp-state-block-500000.json b/migrate/v0_13/testdata/kava-4-cdp-state-block-500000.json new file mode 100644 index 00000000..9651d7a4 --- /dev/null +++ b/migrate/v0_13/testdata/kava-4-cdp-state-block-500000.json @@ -0,0 +1,29102 @@ +{ + "cdps": [ + { + "accumulated_fees": { + "amount": "275155", + "denom": "usdx" + }, + "collateral": { + "amount": "1499799998000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "2", + "owner": "kava19txnej5reyyun4cadgq3kt7ynwpew364kuvfuu", + "principal": { + "amount": "265218316213", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "275463", + "denom": "usdx" + }, + "collateral": { + "amount": "303353300", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:43.739056413Z", + "id": "3", + "owner": "kava1x0rpv6jgfk6yyrvjxp93wq2usjyy9pvl90yppz", + "principal": { + "amount": "25429541", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "25701", + "denom": "usdx" + }, + "collateral": { + "amount": "750046499", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:43.897016316Z", + "id": "6", + "owner": "kava1gzc54u4p67hh9r4m9vcml3ke9fc29tplvvaev3", + "principal": { + "amount": "43634173", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "379480", + "denom": "usdx" + }, + "collateral": { + "amount": "1121546242", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:27.75505786Z", + "id": "8", + "owner": "kava1nmvvhte2j225kvt0gssranmtzhcz50qyzecgsm", + "principal": { + "amount": "70516742", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "503878", + "denom": "usdx" + }, + "collateral": { + "amount": "533307948", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:27.75505786Z", + "id": "9", + "owner": "kava1qa5tpxdy9r636nt2ze76g8k5h6zce807z4tksg", + "principal": { + "amount": "47637510", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "7207472", + "denom": "usdx" + }, + "collateral": { + "amount": "39341407849662", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "13", + "owner": "kava12lsjquv3xrzyu27gyzuxtsmydk8akufznj8qsc", + "principal": { + "amount": "6956965847619", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "46163", + "denom": "usdx" + }, + "collateral": { + "amount": "68490588", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:09.136574316Z", + "id": "17", + "owner": "kava1rsla7s992jeyyaqzaszyljllrvnu6usssp802d", + "principal": { + "amount": "10330270", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "887980", + "denom": "usdx" + }, + "collateral": { + "amount": "1000000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:43.897016316Z", + "id": "18", + "owner": "kava1d6rxxma8uvneyda9fne4qzp7wxdd88vqu4x8qd", + "principal": { + "amount": "100546553", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "285188", + "denom": "usdx" + }, + "collateral": { + "amount": "25390911876", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "19", + "owner": "kava1u4p6a2yse66ewfndw4j7ppsa777vdcex3m4n9s", + "principal": { + "amount": "4177654409", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "12898", + "denom": "usdx" + }, + "collateral": { + "amount": "1089988748", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "20", + "owner": "kava1w05lzr3tj72n33vam3v0qddq05hf605a6k92u5", + "principal": { + "amount": "171260985", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "93727", + "denom": "usdx" + }, + "collateral": { + "amount": "14550030222", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "21", + "owner": "kava1ac6rmjtm8fy5du7twerkltwn20u6augkkuqngh", + "principal": { + "amount": "1947566922", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "110180", + "denom": "usdx" + }, + "collateral": { + "amount": "88268546", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "22", + "owner": "kava1e8xjfylam4nvugcmkxwvuxh22uvvad5vknu4yh", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "4367", + "denom": "usdx" + }, + "collateral": { + "amount": "7999984500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "23", + "owner": "kava1rea6zxqq78klh7uhf78juqp9nmtl53j7hsnquk", + "principal": { + "amount": "1466333572", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "6138", + "denom": "usdx" + }, + "collateral": { + "amount": "79993000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:03:21.52930318Z", + "id": "24", + "owner": "kava14pxuw9zzug0yvmevfzqas792mtnlmtqkc3uups", + "principal": { + "amount": "11269011", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "36379", + "denom": "usdx" + }, + "collateral": { + "amount": "100123000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "25", + "owner": "kava1kajy6ha74la3t7z8xhketrgd5a6jvlu7lhdw2f", + "principal": { + "amount": "13593639", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1193347", + "denom": "usdx" + }, + "collateral": { + "amount": "1099985500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "26", + "owner": "kava1r8jvmxp6hgu4qh3wevs6c06vyfy5gx0eh2amx8", + "principal": { + "amount": "157709981", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "7988967", + "denom": "usdx" + }, + "collateral": { + "amount": "11332962000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "27", + "owner": "kava1q6l5a3ar2la208ekmj6cknk4k787l3anz8r9n0", + "principal": { + "amount": "1140000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "22092", + "denom": "usdx" + }, + "collateral": { + "amount": "45478373051", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "28", + "owner": "kava1dpcgtp7hjvspg7nxpj7c7j25lnyyrau0g72jkd", + "principal": { + "amount": "6790180292", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3174098", + "denom": "usdx" + }, + "collateral": { + "amount": "16226006196", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "29", + "owner": "kava15m5rxv4fut3766luadmxsrxljcs9fvy4afml3f", + "principal": { + "amount": "1538727323", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "35509", + "denom": "usdx" + }, + "collateral": { + "amount": "122733500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:20.453076633Z", + "id": "32", + "owner": "kava17xg8s04tmy57rzhfyfe5ec5xgypeqlpyeekc20", + "principal": { + "amount": "17013608", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "233", + "denom": "usdx" + }, + "collateral": { + "amount": "184987000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:03:52.213324724Z", + "id": "33", + "owner": "kava14702q7mchqfnnhgmqwrhrpj6lcnu4ahz43rg4l", + "principal": { + "amount": "27060893", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "149744", + "denom": "usdx" + }, + "collateral": { + "amount": "2628654500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "36", + "owner": "kava1en7rx4gygys7ah237vt2tq8wwph40mx9ulwu0s", + "principal": { + "amount": "380172737", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2607845", + "denom": "usdx" + }, + "collateral": { + "amount": "4157903615", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "37", + "owner": "kava126fy66c0pnh76xlq54tw043u0hchacpeu0ytwy", + "principal": { + "amount": "240000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1535", + "denom": "usdx" + }, + "collateral": { + "amount": "204696876", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:14.400991279Z", + "id": "38", + "owner": "kava1w0yg5qrrxg8s0ruxyw9e3qhxqtm5l3fk7pn3d9", + "principal": { + "amount": "28932406", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "28839", + "denom": "usdx" + }, + "collateral": { + "amount": "250000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:02:09.942783911Z", + "id": "39", + "owner": "kava1fcfus4u2zt8nr4srvm0g9xzh39r6m6qvp2kde3", + "principal": { + "amount": "10121331", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3415561", + "denom": "usdx" + }, + "collateral": { + "amount": "4999999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "40", + "owner": "kava1cheyls7y2uj7yzmdjeeaaevz463n66ar5lrq8l", + "principal": { + "amount": "400000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "831926", + "denom": "usdx" + }, + "collateral": { + "amount": "11400761500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "42", + "owner": "kava1syhk5r2wrm8vtf6q4dtlu7eag2x74zp3zag0mj", + "principal": { + "amount": "1742816367", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "12519991", + "denom": "usdx" + }, + "collateral": { + "amount": "19852960968", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "43", + "owner": "kava1hwww870p9wdhxs6kzv0x9eqdcp3p75wyqvmn7j", + "principal": { + "amount": "1111606990", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "187624", + "denom": "usdx" + }, + "collateral": { + "amount": "19900000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "44", + "owner": "kava1x7zvs79jzdyhr4h69vtkms2p7k8he4g3u43mym", + "principal": { + "amount": "3366825547", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1446481", + "denom": "usdx" + }, + "collateral": { + "amount": "1399961500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "45", + "owner": "kava1w8lks5mcdvhvjjje9clhysel0j56qjfaudsvjk", + "principal": { + "amount": "198726354", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "129924", + "denom": "usdx" + }, + "collateral": { + "amount": "148000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "46", + "owner": "kava1zyupq6ueyzexdc0qyspax9x3qg0tpkuqzv0l4w", + "principal": { + "amount": "12555297", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "203720", + "denom": "usdx" + }, + "collateral": { + "amount": "7908444605", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "47", + "owner": "kava19jygxtwjal2eu3jmffaftvzwmflgq3gvusm5zl", + "principal": { + "amount": "961882565", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "206058", + "denom": "usdx" + }, + "collateral": { + "amount": "474914875", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:31.545909484Z", + "id": "48", + "owner": "kava1f46llpx6gna2erh3572krdlsugpxdpxa4mxwrs", + "principal": { + "amount": "31164712", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1564049", + "denom": "usdx" + }, + "collateral": { + "amount": "50009243000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "49", + "owner": "kava1fxxdrdrwaqlvatxc6ah2vg6dug72fmvcc4lz44", + "principal": { + "amount": "6031767593", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "189128", + "denom": "usdx" + }, + "collateral": { + "amount": "2850785500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "50", + "owner": "kava1d5axvgqqx92af7pmmakc7x9z3whjrzaakqdmr3", + "principal": { + "amount": "352635951", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "37594", + "denom": "usdx" + }, + "collateral": { + "amount": "101472124", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:00:22.713382299Z", + "id": "51", + "owner": "kava1ajd3v4u8548mp5ffakhm523hr8auz5ztwqd9mm", + "principal": { + "amount": "15014825", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "110251", + "denom": "usdx" + }, + "collateral": { + "amount": "110666628", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "53", + "owner": "kava1cpcs7j777fk2lmqkchz7d36d4k4upx0fjnsgpq", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1367", + "denom": "usdx" + }, + "collateral": { + "amount": "75285412", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:58:40.320250584Z", + "id": "54", + "owner": "kava1rsmsfmjuzywp55aw50vf0u9tah0758z5z509e2", + "principal": { + "amount": "10530031", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1682480", + "denom": "usdx" + }, + "collateral": { + "amount": "1654546137", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "55", + "owner": "kava1tpgwq3lzjn0fcs7lexx675pya4s6al5wvhcl8x", + "principal": { + "amount": "231353142", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "4591", + "denom": "usdx" + }, + "collateral": { + "amount": "615845000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:43.897016316Z", + "id": "56", + "owner": "kava1ltctafhsemwxvdkeygn5dxcwumjg85vj5skrha", + "principal": { + "amount": "81230796", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "526793", + "denom": "usdx" + }, + "collateral": { + "amount": "593243069", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "57", + "owner": "kava1pmxcrgrrp86rqdaane93s3659ulc8qqn2pe933", + "principal": { + "amount": "50162142", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "627827", + "denom": "usdx" + }, + "collateral": { + "amount": "700000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:14.400991279Z", + "id": "58", + "owner": "kava1ws3mcma3qfyq83ddg75p4e8h5xry7wufs5wt5r", + "principal": { + "amount": "58889180", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "42605", + "denom": "usdx" + }, + "collateral": { + "amount": "85011002", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "60", + "owner": "kava1tzxxf6575nmvlwpqvshlad5uqv59arcs65us4a", + "principal": { + "amount": "10000005", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "88359", + "denom": "usdx" + }, + "collateral": { + "amount": "156822736", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:03:36.027198424Z", + "id": "62", + "owner": "kava15hz5fv6qmtjgukej5yc5axgzaklrwz32h5h96g", + "principal": { + "amount": "10228765", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "109605", + "denom": "usdx" + }, + "collateral": { + "amount": "253419438", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "65", + "owner": "kava16mhvkn30xnpxxegcf5354udj3h6qqj8n4889sg", + "principal": { + "amount": "10002415", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "7975380", + "denom": "usdx" + }, + "collateral": { + "amount": "11504824000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "66", + "owner": "kava1d6c4pv4f6vzp5egmxarese8kma8h8q4vh6edy9", + "principal": { + "amount": "936500517", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "930", + "denom": "usdx" + }, + "collateral": { + "amount": "2599000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "67", + "owner": "kava1a7vmnk0qfwuxq0jsek3hr798xutu24ga78s3ys", + "principal": { + "amount": "387446648", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "10152784", + "denom": "usdx" + }, + "collateral": { + "amount": "240148621017", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "68", + "owner": "kava1f98urpz5jj0tfhm0dy6dguk8qp4fq8yr7g0fyq", + "principal": { + "amount": "31067045715", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "326159", + "denom": "usdx" + }, + "collateral": { + "amount": "50182925127", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "69", + "owner": "kava18tt04xwqw38tcxplseymz8hyrgtd7tdpmlnt86", + "principal": { + "amount": "7799721833", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "44421", + "denom": "usdx" + }, + "collateral": { + "amount": "100680062", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "74", + "owner": "kava10zwxdhtwnagvx0lmj8jjzswrtuvutmap9gpsts", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "37887", + "denom": "usdx" + }, + "collateral": { + "amount": "67155552", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "75", + "owner": "kava1qzsu6v4w3g9a8vwu67mcze7myjrnd75lwyk457", + "principal": { + "amount": "10000196", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "6614", + "denom": "usdx" + }, + "collateral": { + "amount": "110664667", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "77", + "owner": "kava1s5le5df46lk8tehuqhyqj9tka5a9jpx0ym3f7l", + "principal": { + "amount": "11049314", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "171548", + "denom": "usdx" + }, + "collateral": { + "amount": "4971546794", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "81", + "owner": "kava1mf3n0ym4eavgkcmazjx7v64a3a8x6nv3hrymdy", + "principal": { + "amount": "818768026", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "63416", + "denom": "usdx" + }, + "collateral": { + "amount": "99831345", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:02:41.472293663Z", + "id": "82", + "owner": "kava19q9us9uav8e2ua7zwlltmvgrhvr29nxttner5y", + "principal": { + "amount": "13540852", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "8557", + "denom": "usdx" + }, + "collateral": { + "amount": "225223570", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:36.983876875Z", + "id": "83", + "owner": "kava1evptartvf3mza08d3782wfdd24l8jzukrsuf44", + "principal": { + "amount": "25001481", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "7055762", + "denom": "usdx" + }, + "collateral": { + "amount": "10317150541", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "84", + "owner": "kava18jsynppwggcy6pde2t43ntsx45rh7e6a5dppc2", + "principal": { + "amount": "700000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2289420", + "denom": "usdx" + }, + "collateral": { + "amount": "4599998000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "86", + "owner": "kava1fts25suh92la0hal4qlsh2799xg43phrnyrle4", + "principal": { + "amount": "415998724", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "213907", + "denom": "usdx" + }, + "collateral": { + "amount": "594648617", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "87", + "owner": "kava1hsf53nfvxng5sd77hgkt0kam0t5e33xucs3apx", + "principal": { + "amount": "69326167", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "5783", + "denom": "usdx" + }, + "collateral": { + "amount": "534886500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:02:09.942783911Z", + "id": "88", + "owner": "kava1dmhhw04s4mlrsu35rn5y5xuyxx5zumuxg4pptw", + "principal": { + "amount": "10132819", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "24173", + "denom": "usdx" + }, + "collateral": { + "amount": "292902982", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:43.897016316Z", + "id": "90", + "owner": "kava1mazzh08dgdqrn8y6khq7snr9jgun3vtlzdhq7c", + "principal": { + "amount": "49000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "37968", + "denom": "usdx" + }, + "collateral": { + "amount": "97122198", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:20.453076633Z", + "id": "92", + "owner": "kava1wwalendqyqytsv2w6gqhpqu0hl4ewlxhadvl58", + "principal": { + "amount": "10638354", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3459988", + "denom": "usdx" + }, + "collateral": { + "amount": "4135994500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "93", + "owner": "kava17mr4tfdx9j6us9efl09esrcmw5tcg2d6ttjk6s", + "principal": { + "amount": "343320079", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3439426", + "denom": "usdx" + }, + "collateral": { + "amount": "5000000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "94", + "owner": "kava179ahnk902wgm7qzr66t5ga0a8euc28ce703jy3", + "principal": { + "amount": "450000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2472663", + "denom": "usdx" + }, + "collateral": { + "amount": "2300000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "97", + "owner": "kava1jl2cf6u0q0g6a64qtsyr340kntysq6v8yrzpk8", + "principal": { + "amount": "370517332", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "52533", + "denom": "usdx" + }, + "collateral": { + "amount": "106405225", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:00:53.396708352Z", + "id": "100", + "owner": "kava1kpdtvxkzmrlhjnkrrlz546pwlu5yp6q7l0wg9v", + "principal": { + "amount": "10111670", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "35274", + "denom": "usdx" + }, + "collateral": { + "amount": "5999823000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "102", + "owner": "kava13sljazg7hetghz33gsr9dmf5x90aj8qt3k7zdn", + "principal": { + "amount": "650865601", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "77697", + "denom": "usdx" + }, + "collateral": { + "amount": "172730500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "107", + "owner": "kava1txgtjvm8nvrmtxvvwrasuer54d4urxplvt49fd", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1791760", + "denom": "usdx" + }, + "collateral": { + "amount": "2999724000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "109", + "owner": "kava1wkn6z4xjrl2esflpdvxemn0m8hkv34ygh6xeaf", + "principal": { + "amount": "177783642", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "367460", + "denom": "usdx" + }, + "collateral": { + "amount": "201550019000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "111", + "owner": "kava1z9v59sdu65z4hssvhhhpnw0pz9p8y3kfgh0h3p", + "principal": { + "amount": "36130612960", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "112891", + "denom": "usdx" + }, + "collateral": { + "amount": "8324185472", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:34.296774744Z", + "id": "112", + "owner": "kava12aazneqltthrxwkc3g4njhwgg9prjylst4m5uh", + "principal": { + "amount": "12644721", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "57154", + "denom": "usdx" + }, + "collateral": { + "amount": "173526945", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:31.545909484Z", + "id": "114", + "owner": "kava1p9plfdwvmzzdsjpukpmvvfh59n94nawzc83jlc", + "principal": { + "amount": "22295606", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "120129", + "denom": "usdx" + }, + "collateral": { + "amount": "199999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:45.943099302Z", + "id": "115", + "owner": "kava1pnh2qs7zfm46chg6k3yy8pad0wuf3rw75rk075", + "principal": { + "amount": "27000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1530", + "denom": "usdx" + }, + "collateral": { + "amount": "82988091", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:03:08.223718604Z", + "id": "116", + "owner": "kava1njys2va5d4th3h6vfrspj7c2plmu8k7r7mc4kt", + "principal": { + "amount": "13497962", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "162869", + "denom": "usdx" + }, + "collateral": { + "amount": "200962500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:03:28.737551656Z", + "id": "117", + "owner": "kava1uw6dj6dmrzp0rw02sy7rk9yqqncu7flf28ku0u", + "principal": { + "amount": "22190000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "134766", + "denom": "usdx" + }, + "collateral": { + "amount": "13711077897", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "118", + "owner": "kava1m33vlnaxcrpn43vrsdwa0er6gljek75297g0c6", + "principal": { + "amount": "2187302864", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "108690", + "denom": "usdx" + }, + "collateral": { + "amount": "179999995", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "119", + "owner": "kava1wg6awxhucnrp7672vcrxq88uwas7gdlsljxfne", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2111862", + "denom": "usdx" + }, + "collateral": { + "amount": "2561224250", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "120", + "owner": "kava1kr7cckmy23tlj4d5urnsclsvxsagusn7kzqs3p", + "principal": { + "amount": "241316390", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "554892", + "denom": "usdx" + }, + "collateral": { + "amount": "12699898000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "121", + "owner": "kava1htrxzxfyek3n62d0jxcygeqflwkmvwslacrr74", + "principal": { + "amount": "2012022388", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "112906", + "denom": "usdx" + }, + "collateral": { + "amount": "245854314", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:02:41.472293663Z", + "id": "122", + "owner": "kava1xspqeczcwpcj7ts3udyxstt33dhc28s0c9ekkx", + "principal": { + "amount": "18195265", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "383142", + "denom": "usdx" + }, + "collateral": { + "amount": "46580963451", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "125", + "owner": "kava15aemgl7ymdqc80wczqynms2wz0efvsf4hs0dhj", + "principal": { + "amount": "6558943638", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "34647", + "denom": "usdx" + }, + "collateral": { + "amount": "4878087619", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "126", + "owner": "kava1z0u0efzn8llallan08kenpuj262etz9392phf4", + "principal": { + "amount": "700046591", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3705", + "denom": "usdx" + }, + "collateral": { + "amount": "66759508", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "127", + "owner": "kava14p5fs6wrqvm0sf908e4f439m3fn54v78em4fl2", + "principal": { + "amount": "10000181", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "438967", + "denom": "usdx" + }, + "collateral": { + "amount": "1250511274", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "128", + "owner": "kava1cvg39q0es6npwwaazzvd3hwme8suf0zj2zjft8", + "principal": { + "amount": "120340865", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "394", + "denom": "usdx" + }, + "collateral": { + "amount": "136428994", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:09.136574316Z", + "id": "130", + "owner": "kava1mdm5595gw7n2yrfa6fjdrk2xwzn4njkj2akvq4", + "principal": { + "amount": "10011612", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "187263", + "denom": "usdx" + }, + "collateral": { + "amount": "5893653156", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "131", + "owner": "kava1lat5vnu7qj6wlhlqcvevd2q8euy6z5kwqqhk33", + "principal": { + "amount": "659151639", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "59356", + "denom": "usdx" + }, + "collateral": { + "amount": "130892506", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:57:13.731216849Z", + "id": "132", + "owner": "kava1n3wyrlf89nh0r8ckfum3xa9gjtvpus3ffeh9mw", + "principal": { + "amount": "10044342", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "88223", + "denom": "usdx" + }, + "collateral": { + "amount": "506477381", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:00:22.713382299Z", + "id": "135", + "owner": "kava12g2hjsf6wgxv72jepy7n6vv7t30jqy0ev798ys", + "principal": { + "amount": "14844603", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "371810", + "denom": "usdx" + }, + "collateral": { + "amount": "688712887", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "138", + "owner": "kava1yp870cqtd52augmyqqnnzyn43p20jvtz0jttj9", + "principal": { + "amount": "50000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1790572", + "denom": "usdx" + }, + "collateral": { + "amount": "2199861500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "139", + "owner": "kava16h4qwf5gjuvhnaj4hn943gc6z5smvg07y3p4g0", + "principal": { + "amount": "180859560", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "334711", + "denom": "usdx" + }, + "collateral": { + "amount": "536961500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:18.15526764Z", + "id": "140", + "owner": "kava1rsan6tsut8upy9m4xq3jjprkg5g7td7d5n7t9a", + "principal": { + "amount": "31546488", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "8387767", + "denom": "usdx" + }, + "collateral": { + "amount": "15599923510", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "141", + "owner": "kava1acqutt8qfe66c0nnhlzl7rmadfnuxnuaetehfh", + "principal": { + "amount": "1443370506", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "61578", + "denom": "usdx" + }, + "collateral": { + "amount": "11919078365", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "142", + "owner": "kava1xjqgqjx0qty6usulkl5qs9fphtysjx3zkmz0aj", + "principal": { + "amount": "1835735503", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "7581680", + "denom": "usdx" + }, + "collateral": { + "amount": "7539967934", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "143", + "owner": "kava1sxhs7nrnmz5ypxjjx809wk92wy3uwz0x456r8w", + "principal": { + "amount": "1024940493", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1416687", + "denom": "usdx" + }, + "collateral": { + "amount": "1999884500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "144", + "owner": "kava12aw587tn9nmmlvnq920hj9ykxewazhszjjrvtj", + "principal": { + "amount": "221000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2068", + "denom": "usdx" + }, + "collateral": { + "amount": "200111925", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:14.400991279Z", + "id": "146", + "owner": "kava1k4p64mj6mumgqtj69h632qyhhy3ycx0hd9rmcn", + "principal": { + "amount": "20173312", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "7874", + "denom": "usdx" + }, + "collateral": { + "amount": "129890177", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "147", + "owner": "kava1mmk5cms47rwr3dhmc5c5glquhzqphl4tz0k2ch", + "principal": { + "amount": "20293633", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3863551", + "denom": "usdx" + }, + "collateral": { + "amount": "4790000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "148", + "owner": "kava1ftc84gde38ar4n94qw27hqngmfjgnhkz7vcue2", + "principal": { + "amount": "375000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "63451", + "denom": "usdx" + }, + "collateral": { + "amount": "157840000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:28.231878135Z", + "id": "150", + "owner": "kava1ta5r404ddf3eg469feyp3vufvjrjzrwl32tztm", + "principal": { + "amount": "20068643", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "108010", + "denom": "usdx" + }, + "collateral": { + "amount": "98999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "152", + "owner": "kava14n35k79dd8v0uvnrv78mlyu9z7ms3xvvxmgqp9", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "39762", + "denom": "usdx" + }, + "collateral": { + "amount": "186803826", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "155", + "owner": "kava1d6zryvkfx9ee8l8xtjxq3l084zjunygjahj5a6", + "principal": { + "amount": "10000005", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1808518", + "denom": "usdx" + }, + "collateral": { + "amount": "13098997000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "156", + "owner": "kava1pmevzvgte6ktrr6lrpmqhd99gwd56dldcshlcs", + "principal": { + "amount": "1380764726", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "35273", + "denom": "usdx" + }, + "collateral": { + "amount": "4514000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "157", + "owner": "kava1d4053k27uwemf05wjzd8jwgce872jadk24g6zc", + "principal": { + "amount": "603863292", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "104407", + "denom": "usdx" + }, + "collateral": { + "amount": "506296525", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:34.296774744Z", + "id": "158", + "owner": "kava19c3nfs44hnvj79nhlgnejc72l3rehetjdeg22u", + "principal": { + "amount": "10535886", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "88760", + "denom": "usdx" + }, + "collateral": { + "amount": "219831500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:02:59.644377189Z", + "id": "161", + "owner": "kava1umpnjpmarpf0zhplq2lmfvfftzzc9n5j8dl5wr", + "principal": { + "amount": "20794851", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1007641", + "denom": "usdx" + }, + "collateral": { + "amount": "1239861500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:43.897016316Z", + "id": "164", + "owner": "kava14cu4p23z8hmdaxgsf4kw5umdwavlag0e575rqw", + "principal": { + "amount": "101100290", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "54592", + "denom": "usdx" + }, + "collateral": { + "amount": "8632985000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "165", + "owner": "kava1m37v42df7s50lh9l7rfa8wr6wffply4kzluvr0", + "principal": { + "amount": "1351255844", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1509", + "denom": "usdx" + }, + "collateral": { + "amount": "95333866", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:05.765073985Z", + "id": "166", + "owner": "kava1lwqsm6rlctyy4kyy46k9637zdmuscpr8p7faz5", + "principal": { + "amount": "13946288", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "93381", + "denom": "usdx" + }, + "collateral": { + "amount": "225000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "168", + "owner": "kava1xjtc2yk7v8tr7ulw85s7x04z255h70h8rp49hq", + "principal": { + "amount": "10001930", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "9105949", + "denom": "usdx" + }, + "collateral": { + "amount": "14492501291", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "169", + "owner": "kava1au4duea0pe6a5dyzt5gfx6x449k6emqz0nczhl", + "principal": { + "amount": "1354691996", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "55879", + "denom": "usdx" + }, + "collateral": { + "amount": "200000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:00:08.102456799Z", + "id": "170", + "owner": "kava1094f93evptxeg9nl82pn5wv2yrhqglqpq4wyvf", + "principal": { + "amount": "11926946", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "118129", + "denom": "usdx" + }, + "collateral": { + "amount": "105000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:03:28.737551656Z", + "id": "172", + "owner": "kava1twq0lv44v9hl3zl2v2799pnndr60w6g348ayxd", + "principal": { + "amount": "11000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2269", + "denom": "usdx" + }, + "collateral": { + "amount": "129000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:00:44.590106804Z", + "id": "173", + "owner": "kava17kwqz4r3fnh4cderhza8lnq63su4drfzeqra7m", + "principal": { + "amount": "12105560", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "675906", + "denom": "usdx" + }, + "collateral": { + "amount": "4457745351", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "174", + "owner": "kava1ljex7663xnw98455y4fgtref0znkt2u0yglh6k", + "principal": { + "amount": "163530739", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "126557", + "denom": "usdx" + }, + "collateral": { + "amount": "199961500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:03:36.027198424Z", + "id": "177", + "owner": "kava1wgtny83g504gxpfj0f36cx6ztrfqlk0wj4pese", + "principal": { + "amount": "11820524", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "9307", + "denom": "usdx" + }, + "collateral": { + "amount": "200181296", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:05.765073985Z", + "id": "180", + "owner": "kava12qgnr0f8v9q3uuzhpjudlw90v6map4pdu5cfdc", + "principal": { + "amount": "10200000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "811052", + "denom": "usdx" + }, + "collateral": { + "amount": "700000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:27.75505786Z", + "id": "183", + "owner": "kava1wc4pmp258ns0rk2vvknjz5rwnpju378k82hhwd", + "principal": { + "amount": "80000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "333162", + "denom": "usdx" + }, + "collateral": { + "amount": "5624934939", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "184", + "owner": "kava1hfmx6fngjmjuwvs3tmaev85dduq69w2jkchv8x", + "principal": { + "amount": "864780484", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "221443", + "denom": "usdx" + }, + "collateral": { + "amount": "1382979946", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "185", + "owner": "kava13tzqh4zcdu8t87zhc9dz9jvre788mv53h9kcgr", + "principal": { + "amount": "195931690", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "102332", + "denom": "usdx" + }, + "collateral": { + "amount": "132265818", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "186", + "owner": "kava1htlex570h6jy97g7dt6t254gt8g8p06s6re6rx", + "principal": { + "amount": "10000214", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "122260", + "denom": "usdx" + }, + "collateral": { + "amount": "99861500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:11.309262057Z", + "id": "188", + "owner": "kava1x6vr5x2ln3t8p0v75d25j2levjzjs26rvzfm69", + "principal": { + "amount": "11504377", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "794162", + "denom": "usdx" + }, + "collateral": { + "amount": "3899760500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "194", + "owner": "kava1la226f3y75shcn7ath84h3wqft3az4qqf9sd2m", + "principal": { + "amount": "402459198", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "105479", + "denom": "usdx" + }, + "collateral": { + "amount": "240000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "195", + "owner": "kava1hrhn3kpm3euny5u7ua783enyzjm27mf2l6l9rh", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "90504", + "denom": "usdx" + }, + "collateral": { + "amount": "363621435", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:05.765073985Z", + "id": "196", + "owner": "kava1667fn3eu2r57uj6w8t4zpz7rak73kawxqtujpm", + "principal": { + "amount": "30059251", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1620965", + "denom": "usdx" + }, + "collateral": { + "amount": "33404315684", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "198", + "owner": "kava1v3atcfl7hmesuwdp8s7rshveuynqkx0vdqvs2l", + "principal": { + "amount": "4934696214", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "98069", + "denom": "usdx" + }, + "collateral": { + "amount": "152505102000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "199", + "owner": "kava1mz2vfw29fzkg4yj9wfh99nkgx46unhrxtyxqhc", + "principal": { + "amount": "27028872012", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2021154", + "denom": "usdx" + }, + "collateral": { + "amount": "2500000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "201", + "owner": "kava175mrr57z7t3kr7mgxc5rut244nsl4y69ynaak2", + "principal": { + "amount": "320000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "200328", + "denom": "usdx" + }, + "collateral": { + "amount": "4109955500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "209", + "owner": "kava1egcn53hpwr73yqrl927gjrrxmjsu3nz74km58n", + "principal": { + "amount": "488112958", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "107997", + "denom": "usdx" + }, + "collateral": { + "amount": "14332460104", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "210", + "owner": "kava1zdlmh3s8wea9xsjk59n3fuy73lw4wn435dw80j", + "principal": { + "amount": "2251106297", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "64176018", + "denom": "usdx" + }, + "collateral": { + "amount": "97950382500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "212", + "owner": "kava12qjltp2vkqmpp29s97l3esk2ek5zjsl9lnlfj4", + "principal": { + "amount": "11941291007", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "359253", + "denom": "usdx" + }, + "collateral": { + "amount": "630788993", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:02.663985461Z", + "id": "214", + "owner": "kava17qau97j220xw0ssptvh7vnl4wqak6e2pgtne35", + "principal": { + "amount": "40000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "4930811", + "denom": "usdx" + }, + "collateral": { + "amount": "6605883474", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "220", + "owner": "kava1lq0aggmkh3nk5zuzwsv5g2pph9cp0xl4vuh4t7", + "principal": { + "amount": "500000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "95021", + "denom": "usdx" + }, + "collateral": { + "amount": "137861617", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "221", + "owner": "kava1fewhhjak24u0s54jw9s7pdluw2aqw4cra2el42", + "principal": { + "amount": "10002091", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "119665", + "denom": "usdx" + }, + "collateral": { + "amount": "181855384467", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "223", + "owner": "kava14m0dtdvs9pqeqg74g7jnxcr9tkpl4maa7r5mkv", + "principal": { + "amount": "32045728064", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "18753", + "denom": "usdx" + }, + "collateral": { + "amount": "2045659746", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "224", + "owner": "kava1jzfled0eeaalypkzj6p5dmesav2va3tfzaa8cl", + "principal": { + "amount": "300289565", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "57629", + "denom": "usdx" + }, + "collateral": { + "amount": "84315550", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "225", + "owner": "kava10qzu70ezk0rajhj6wrztt8y4lc556sqxmlc6mz", + "principal": { + "amount": "10000561", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "6792429", + "denom": "usdx" + }, + "collateral": { + "amount": "29994238985", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "226", + "owner": "kava1p8nd9vexkqhcenzj3cuju640q4zt35tdf0hk4g", + "principal": { + "amount": "3115865246", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3330795", + "denom": "usdx" + }, + "collateral": { + "amount": "6034659040", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "228", + "owner": "kava10tejts3kusudtpqfpv9rsxhealyfqs3q25zqk9", + "principal": { + "amount": "607322207", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "115410", + "denom": "usdx" + }, + "collateral": { + "amount": "13649307500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "230", + "owner": "kava1smm4h4uynsdq7ymahr7h4c89hdll8fpry742kp", + "principal": { + "amount": "2004477668", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "188685", + "denom": "usdx" + }, + "collateral": { + "amount": "574537974", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:36.983876875Z", + "id": "231", + "owner": "kava1w20u97emzxc257hdyaywdxnyxs0mx586a5nxe2", + "principal": { + "amount": "41860214", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "401", + "denom": "usdx" + }, + "collateral": { + "amount": "199861500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:03:52.213324724Z", + "id": "233", + "owner": "kava10ucdtdqqnkhh26z4zqk6ewwp2ld03etkzeskcz", + "principal": { + "amount": "28618603", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "79647", + "denom": "usdx" + }, + "collateral": { + "amount": "89999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "236", + "owner": "kava1sfj08ymeqfevqk8w3fmhrm8fmdc9dqa8ew0egu", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "44274", + "denom": "usdx" + }, + "collateral": { + "amount": "5199723000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "238", + "owner": "kava1gqfh80j9fe95hczvew62d527agntsp7je4ddrw", + "principal": { + "amount": "840306640", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "15491356", + "denom": "usdx" + }, + "collateral": { + "amount": "21009884500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "240", + "owner": "kava18utzytkj0unzevcm4jzxncu95prc8x5wqcnt9n", + "principal": { + "amount": "3001000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2094500", + "denom": "usdx" + }, + "collateral": { + "amount": "5078401785", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "241", + "owner": "kava1cfyddlz92xuk73kp5du820eu4h92fy3rs85k4w", + "principal": { + "amount": "481338955", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1189965", + "denom": "usdx" + }, + "collateral": { + "amount": "40636064040", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "242", + "owner": "kava1fuwnpvv6heued9mmhlphpwgyu4fu0tzvcan9u9", + "principal": { + "amount": "4169206047", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "54743", + "denom": "usdx" + }, + "collateral": { + "amount": "1009997000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:36.711042819Z", + "id": "243", + "owner": "kava1zax5vgs3u9tn64puy7jg0a9tt4h7l652p2qjjn", + "principal": { + "amount": "23942255", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "588581", + "denom": "usdx" + }, + "collateral": { + "amount": "1101467619", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:27.75505786Z", + "id": "244", + "owner": "kava1f00asq9t4fmvmy3n5p950t8njq3vptdgmfg62v", + "principal": { + "amount": "79118419", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "11073017", + "denom": "usdx" + }, + "collateral": { + "amount": "29699823000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "245", + "owner": "kava1jvggf4u68jvlm4dk3auh4ns2fuuph2w2yr7utf", + "principal": { + "amount": "2953286422", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "819380", + "denom": "usdx" + }, + "collateral": { + "amount": "142899949000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "246", + "owner": "kava1vn75l627k2p97wzu2sl3mhsxj285lvyrp4z866", + "principal": { + "amount": "12015429736", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "260714", + "denom": "usdx" + }, + "collateral": { + "amount": "889998000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:36.711042819Z", + "id": "247", + "owner": "kava1wyqhajn6mshcmx0j5qqzdmd87c7a83c5f4c587", + "principal": { + "amount": "85050544", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "29785", + "denom": "usdx" + }, + "collateral": { + "amount": "4732418000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "248", + "owner": "kava1lmdqakjz5p7gjw3q7333kkgc2xje4d6zzu544k", + "principal": { + "amount": "680565341", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "36786502", + "denom": "usdx" + }, + "collateral": { + "amount": "100009998000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "249", + "owner": "kava10f52vl8ga9map8pjlyeypglcrd9yxnn503gfuh", + "principal": { + "amount": "7557060300", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "6985759", + "denom": "usdx" + }, + "collateral": { + "amount": "10000000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "250", + "owner": "kava1q56vft29tyu64lr24mj9rehxgdvrskj8puyjx5", + "principal": { + "amount": "1000000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1763495", + "denom": "usdx" + }, + "collateral": { + "amount": "102126763500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "251", + "owner": "kava1u205gp2kxm7kj2ta2yhtpazdyc97xgy8e3re7k", + "principal": { + "amount": "11311847033", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3819648", + "denom": "usdx" + }, + "collateral": { + "amount": "8297257199", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "252", + "owner": "kava1hfqe298wulu4uhqgj0h8sggc3akrgyelavzszv", + "principal": { + "amount": "863926387", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "246603", + "denom": "usdx" + }, + "collateral": { + "amount": "30149861500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "253", + "owner": "kava1k33pgvv8fs875ht5erf4qvqpdrhtlckt2twd93", + "principal": { + "amount": "3866483734", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1474345", + "denom": "usdx" + }, + "collateral": { + "amount": "2843220500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "254", + "owner": "kava1n7mfen688q8yy3ppwpl2maymtfrh5u2a8c7e33", + "principal": { + "amount": "208961555", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "224557", + "denom": "usdx" + }, + "collateral": { + "amount": "6497259922", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "255", + "owner": "kava1ynemgmzp3mfevzj5e6zcg97z2dmjgvuysgzyyx", + "principal": { + "amount": "945185736", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "446913", + "denom": "usdx" + }, + "collateral": { + "amount": "860000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:36.711042819Z", + "id": "256", + "owner": "kava1vpvj0w7spgzx4rkhkv4j4y0tj58dc8endq99s6", + "principal": { + "amount": "60000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2422951", + "denom": "usdx" + }, + "collateral": { + "amount": "3789926071", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "257", + "owner": "kava1mfc7p3yt6r33qsee677wlwa4zr5u09sdex8txt", + "principal": { + "amount": "323218734", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "19801", + "denom": "usdx" + }, + "collateral": { + "amount": "101644000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "259", + "owner": "kava1a50y5udh2knhktmxyczl349a96zpngjvzqrkzu", + "principal": { + "amount": "10000049", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "60939", + "denom": "usdx" + }, + "collateral": { + "amount": "129924000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:03:21.52930318Z", + "id": "260", + "owner": "kava1vqcufyyah03sntzgsz6rfykjtrsfguht2hgw6d", + "principal": { + "amount": "11264802", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1782444", + "denom": "usdx" + }, + "collateral": { + "amount": "2198824000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "261", + "owner": "kava1cerh3sw0m2mpnwdz3a930qd5d7n5nz8s8f4p6w", + "principal": { + "amount": "343341816", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "371574", + "denom": "usdx" + }, + "collateral": { + "amount": "499961500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "262", + "owner": "kava1c5he6km22u7upezmuj3yzvwu6a3u2vmnaunp8d", + "principal": { + "amount": "50000734", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "48717", + "denom": "usdx" + }, + "collateral": { + "amount": "161543210", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:58:40.320250584Z", + "id": "265", + "owner": "kava1gupd5xrnzsaln387044z39lrclxnrjxg2s0rza", + "principal": { + "amount": "10143670", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "25836", + "denom": "usdx" + }, + "collateral": { + "amount": "163644000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:03:59.168880771Z", + "id": "266", + "owner": "kava1jdvt0v2l5mcpmasd2zjk8zpxwkk78a8rfkds0p", + "principal": { + "amount": "22635183", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "20482822", + "denom": "usdx" + }, + "collateral": { + "amount": "30100000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "268", + "owner": "kava1m520r5q3t9qug3ssc52wc9s0876c7v9dde5d6k", + "principal": { + "amount": "3340542201", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "49504", + "denom": "usdx" + }, + "collateral": { + "amount": "269999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "269", + "owner": "kava1w5f7v8wa8jxg9f2c6scufgs7r9gl7npsh570n7", + "principal": { + "amount": "24010725", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "302651", + "denom": "usdx" + }, + "collateral": { + "amount": "677627000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:27.75505786Z", + "id": "271", + "owner": "kava1qxhh4g05dckdzjhe592kv82t50dh9l4ds4ljlm", + "principal": { + "amount": "79298725", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "38630", + "denom": "usdx" + }, + "collateral": { + "amount": "799273233", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:36.711042819Z", + "id": "272", + "owner": "kava19qd98v0twgum4eqln8gcwru8wccv2syu7rcygk", + "principal": { + "amount": "106240165", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3987636", + "denom": "usdx" + }, + "collateral": { + "amount": "8960753805", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "273", + "owner": "kava1mxu3lnm80ynhs2gavu2w2um29pcvkgvceh29ks", + "principal": { + "amount": "725186102", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "232594", + "denom": "usdx" + }, + "collateral": { + "amount": "3397860720", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "274", + "owner": "kava1qg53ggjzzz8e9x9kh9fsk8a4z2dldczrp6j00l", + "principal": { + "amount": "582297327", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "933377", + "denom": "usdx" + }, + "collateral": { + "amount": "1762359738", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "275", + "owner": "kava1tss7dhwa533u8h3v8z43w8656uaxk3fvzhrwzj", + "principal": { + "amount": "180982579", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "5101", + "denom": "usdx" + }, + "collateral": { + "amount": "709861500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:27.75505786Z", + "id": "276", + "owner": "kava1j8ecw7df2t57d0s5qpk8ke2f6d6m7rhuf4mkva", + "principal": { + "amount": "73197731", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "77607", + "denom": "usdx" + }, + "collateral": { + "amount": "99861500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "277", + "owner": "kava1wxvryaw030wwmp3a588wnehwqp9wlv0zn460ek", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "6477000", + "denom": "usdx" + }, + "collateral": { + "amount": "8320342399", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "278", + "owner": "kava184kqpjfpycyza900d7q3gx8nhxt5e0syqmg49w", + "principal": { + "amount": "1151806946", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "878963", + "denom": "usdx" + }, + "collateral": { + "amount": "1684599000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "279", + "owner": "kava1gjxu07sy6cmdxd8gwpqv4ry3epeuszvpkl9p82", + "principal": { + "amount": "198561476", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1679880", + "denom": "usdx" + }, + "collateral": { + "amount": "1999961500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "280", + "owner": "kava1mzt56dpf2d0gdrzarf7p6kd8nnjkpc25fuc3r5", + "principal": { + "amount": "252126354", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "27419739", + "denom": "usdx" + }, + "collateral": { + "amount": "35806987133", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "281", + "owner": "kava16v8kqpw58lmh6pl2wggyheh3pxe7uenzm478ye", + "principal": { + "amount": "3600855659", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "14192", + "denom": "usdx" + }, + "collateral": { + "amount": "84999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:00:01.347323184Z", + "id": "282", + "owner": "kava1gwjt5vxekyxfdgrmyewwkr6uyvj87tfa0mzx2v", + "principal": { + "amount": "10286277", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1040", + "denom": "usdx" + }, + "collateral": { + "amount": "86914598", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:27.75505786Z", + "id": "284", + "owner": "kava1xm5h5v6kwydahmrst577fj3s7u3e5gjwecy5zg", + "principal": { + "amount": "10245441", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1447724", + "denom": "usdx" + }, + "collateral": { + "amount": "2499961500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "285", + "owner": "kava1v6dnz6206d38s729jjewekfz8kyk08m702gr4r", + "principal": { + "amount": "200000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "4250920", + "denom": "usdx" + }, + "collateral": { + "amount": "7999961500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "286", + "owner": "kava14qv83m9csmul9qdgqyafqhhwha8z464s5ppjta", + "principal": { + "amount": "574642567", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "166755", + "denom": "usdx" + }, + "collateral": { + "amount": "4499908828", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "287", + "owner": "kava1tuulhc6twgdtvzd6685ltqgh2adjcuyaxzkyvk", + "principal": { + "amount": "660242294", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3331679", + "denom": "usdx" + }, + "collateral": { + "amount": "4499584500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "288", + "owner": "kava1q2hpn8wjvgygwf8uvtlm99x7jr4az87gu0und9", + "principal": { + "amount": "507260008", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1007", + "denom": "usdx" + }, + "collateral": { + "amount": "99861500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:09.136574316Z", + "id": "289", + "owner": "kava1yj79c8l6rmrnd9kwga9ruetaseh2yxv2f6xe7y", + "principal": { + "amount": "10038000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "123669", + "denom": "usdx" + }, + "collateral": { + "amount": "490000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:55.262259649Z", + "id": "290", + "owner": "kava1ks9u07zl4h3h3q6mlu4t2v7xflwvk332rz8m33", + "principal": { + "amount": "22825990", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "206519", + "denom": "usdx" + }, + "collateral": { + "amount": "249861500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:09.136574316Z", + "id": "292", + "owner": "kava1kttpakv8zy8h3q8fc2665rk5k0jj0v4g3d3tsy", + "principal": { + "amount": "27367671", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "5488", + "denom": "usdx" + }, + "collateral": { + "amount": "118092975", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "293", + "owner": "kava1acmwmx66s0htudhn43jgdym0xdphyvnhez6jky", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "831428", + "denom": "usdx" + }, + "collateral": { + "amount": "1499861500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "294", + "owner": "kava1dn23hf3h0ysfh8j6t7f6vp95unvfet7qlgrkv4", + "principal": { + "amount": "150904667", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "17599", + "denom": "usdx" + }, + "collateral": { + "amount": "139799581", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "295", + "owner": "kava1jdf8d4s0zcwtg5le0qkya0xsfl85xm4zpv4802", + "principal": { + "amount": "10000949", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1582042", + "denom": "usdx" + }, + "collateral": { + "amount": "3489084250", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "296", + "owner": "kava19r2a7ewaknnp60nvz78f60xqlszlw3msgscg8f", + "principal": { + "amount": "446488287", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "77503", + "denom": "usdx" + }, + "collateral": { + "amount": "100000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "297", + "owner": "kava1uaz20kn9qnf23kcj9tne2glfs4d7vtwt0c66ws", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "15065369", + "denom": "usdx" + }, + "collateral": { + "amount": "20062220557", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "299", + "owner": "kava1rdzc5h94tjfsg38se9zre672z9ccux06ywdlme", + "principal": { + "amount": "2378353352", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "992362", + "denom": "usdx" + }, + "collateral": { + "amount": "98253652312", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "300", + "owner": "kava1d2u28azje7rhqyjtxc2ex8q0cxxpw7dfm7ltq5", + "principal": { + "amount": "15465168752", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "12974", + "denom": "usdx" + }, + "collateral": { + "amount": "1363949000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "301", + "owner": "kava1knu3dygrpnfy92kxqwh0mv3pzylfug6nwk68pd", + "principal": { + "amount": "220829543", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "156502", + "denom": "usdx" + }, + "collateral": { + "amount": "199961500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:36.983876875Z", + "id": "302", + "owner": "kava1a33hz0z6wr728gfy9mf80lhgngdqm28l94n9ej", + "principal": { + "amount": "24998229", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "27501", + "denom": "usdx" + }, + "collateral": { + "amount": "200000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "303", + "owner": "kava1yzmdt6hgpcs8q2tmasls5fksrx8fl78ddj3nzn", + "principal": { + "amount": "20001500", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2710923", + "denom": "usdx" + }, + "collateral": { + "amount": "4081136101", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "306", + "owner": "kava17cptmd6cs2h032pg4jnjdlfjgvhnkcl32evqy3", + "principal": { + "amount": "525000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "576583", + "denom": "usdx" + }, + "collateral": { + "amount": "14999961500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "308", + "owner": "kava1ujpxleqcqugjdulwne6z0du8f5mej55c545pfz", + "principal": { + "amount": "2000258202", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3561", + "denom": "usdx" + }, + "collateral": { + "amount": "61811997", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "310", + "owner": "kava1ym6nku4uur3vz0lp3ur54dkhpll8uhehgfnz8k", + "principal": { + "amount": "10000654", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "46932", + "denom": "usdx" + }, + "collateral": { + "amount": "2294885500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "311", + "owner": "kava12dh2n57a0yq5tp4neux9zk9w62z6hg58gwuta2", + "principal": { + "amount": "228752361", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3462", + "denom": "usdx" + }, + "collateral": { + "amount": "92858000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:55.262259649Z", + "id": "312", + "owner": "kava1r24w3dl5jxke3lt5x5jc2cvjlp97ynmhve8x8e", + "principal": { + "amount": "10000060", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "986568", + "denom": "usdx" + }, + "collateral": { + "amount": "2634033895", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "314", + "owner": "kava1dv0zgqn33sjyyx7jhxt3s9c2ug239t8fnph42q", + "principal": { + "amount": "300948233", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "717015", + "denom": "usdx" + }, + "collateral": { + "amount": "999115120", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "315", + "owner": "kava1yw26hjjy88k4ym5ntu2h6e55pgm2xp8sqy72sw", + "principal": { + "amount": "100000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "4114", + "denom": "usdx" + }, + "collateral": { + "amount": "203117060", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:00:53.396708352Z", + "id": "316", + "owner": "kava1rlr7nzssxt2ls2nnldey272alalsnf6svn4vyj", + "principal": { + "amount": "10105491", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3719504", + "denom": "usdx" + }, + "collateral": { + "amount": "7510761500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "317", + "owner": "kava109a56s0epqwe3emg9786kt7n5urnrscstk04ms", + "principal": { + "amount": "533603302", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "10311", + "denom": "usdx" + }, + "collateral": { + "amount": "111957402", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "319", + "owner": "kava1dwlzzy9c4ge26xh95556pjp6lsg2e66wc64unl", + "principal": { + "amount": "10001845", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "154497", + "denom": "usdx" + }, + "collateral": { + "amount": "200061500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:43.739056413Z", + "id": "320", + "owner": "kava1hxku2c2g4ngum33ewpgyk58wl9he9ces97nw3q", + "principal": { + "amount": "30286328", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3047", + "denom": "usdx" + }, + "collateral": { + "amount": "6546967000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "324", + "owner": "kava1j25le44ttjsrvt5h6k56ytmcn7n50mltw6muxd", + "principal": { + "amount": "1220478827", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2664179", + "denom": "usdx" + }, + "collateral": { + "amount": "12450000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "326", + "owner": "kava17lgpxr5mug8hsmftzlklqyqtlu7mwpzwgqc0aq", + "principal": { + "amount": "1598442453", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "158805", + "denom": "usdx" + }, + "collateral": { + "amount": "199861500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:02:59.644377189Z", + "id": "329", + "owner": "kava12uq64q7k0fvwvly7latfvxgf4t09mpkfm6tg37", + "principal": { + "amount": "20798034", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "46454", + "denom": "usdx" + }, + "collateral": { + "amount": "75859266", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:00:22.713382299Z", + "id": "330", + "owner": "kava1resk3zjgyv9298u2ckkpdz38gekh9myqr6tk4a", + "principal": { + "amount": "10247454", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3516", + "denom": "usdx" + }, + "collateral": { + "amount": "409995000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "331", + "owner": "kava1xxntzlrgekrk7nt9xdh5fk52c2kds2r0al5lmq", + "principal": { + "amount": "49999914", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "438973", + "denom": "usdx" + }, + "collateral": { + "amount": "22654997000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "332", + "owner": "kava1vg6q5k7q6s89lk852dgle8c5fr3rmrrr3jsvhy", + "principal": { + "amount": "2295012206", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "62519", + "denom": "usdx" + }, + "collateral": { + "amount": "149928250", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:36.711042819Z", + "id": "333", + "owner": "kava1cf0ukvyjljkwld5gdx0gc6e3wf9wmyyundw8xa", + "principal": { + "amount": "13673673", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "247525", + "denom": "usdx" + }, + "collateral": { + "amount": "2000999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:27.75505786Z", + "id": "334", + "owner": "kava1uwwcahz5wxd5hyu2xpgxxpselkr6wmzf0q06lk", + "principal": { + "amount": "72680425", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "525855", + "denom": "usdx" + }, + "collateral": { + "amount": "70175305686", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "335", + "owner": "kava16ug360rgcgd460046x97udcd9k0n39rze5qtp9", + "principal": { + "amount": "9595304586", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "698319", + "denom": "usdx" + }, + "collateral": { + "amount": "914774583", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "336", + "owner": "kava1j46re9mh9y63jldgy5g66e3jc0sk0wq6ze9ajl", + "principal": { + "amount": "99176201", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "48652", + "denom": "usdx" + }, + "collateral": { + "amount": "199998000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "337", + "owner": "kava1942dmaf9g8x3s9m6p64d5hsy49pdfa2ux9h205", + "principal": { + "amount": "10336114", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "701391", + "denom": "usdx" + }, + "collateral": { + "amount": "2179961500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "338", + "owner": "kava1wzqa96jrwda3szysudfsu7dzm64rcad2wj4z6w", + "principal": { + "amount": "100000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "45486", + "denom": "usdx" + }, + "collateral": { + "amount": "135208606", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:28.231878135Z", + "id": "339", + "owner": "kava1mka7zvjmznra0wn67f6tfppj0g07ddwznqnefm", + "principal": { + "amount": "20217586", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "17860", + "denom": "usdx" + }, + "collateral": { + "amount": "301902824", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:14.400991279Z", + "id": "341", + "owner": "kava19ftkymerpmf2lq427da377ypednatj467lc7wy", + "principal": { + "amount": "31029015", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "34665", + "denom": "usdx" + }, + "collateral": { + "amount": "4793394312", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "342", + "owner": "kava1hndh9pwsaz5arhtryh8zedtr4kdvdtvcfnvc3d", + "principal": { + "amount": "697786605", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "45678", + "denom": "usdx" + }, + "collateral": { + "amount": "331427379", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:05.765073985Z", + "id": "344", + "owner": "kava1vmgk2zex6wm73hkuna9p9rm343e57xyznszfj7", + "principal": { + "amount": "54566939", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "75577", + "denom": "usdx" + }, + "collateral": { + "amount": "108004194", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "345", + "owner": "kava1zqrpq7jaw9agqhh5e00gf28twfpc2ex05w8sec", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "133564", + "denom": "usdx" + }, + "collateral": { + "amount": "159961500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "347", + "owner": "kava1hwf9g5ffng96qmgr0lxzuyljgrc5ne7e0gk780", + "principal": { + "amount": "18346790", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "83060", + "denom": "usdx" + }, + "collateral": { + "amount": "302093000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:45.943099302Z", + "id": "349", + "owner": "kava18remxg0pxfvrrfkez5lzjtaj6ldlq6hz0g9hy4", + "principal": { + "amount": "29094509", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "75432", + "denom": "usdx" + }, + "collateral": { + "amount": "122917493", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "350", + "owner": "kava16p8lcgmjh6edz622935uvd7rufrl3jtafwdgg5", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "48621", + "denom": "usdx" + }, + "collateral": { + "amount": "134248000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:20.647451252Z", + "id": "351", + "owner": "kava1tmz4v86u8j8cq8yxgh6lensugkzxpql4c7mpxy", + "principal": { + "amount": "10855036", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1430623", + "denom": "usdx" + }, + "collateral": { + "amount": "39099024500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "353", + "owner": "kava1jhjr5gef5dg3cyualy3um2rvn7594r3frtm39l", + "principal": { + "amount": "5185681865", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3559398", + "denom": "usdx" + }, + "collateral": { + "amount": "9974999250", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "354", + "owner": "kava1u5qymm9e7hlarv9g3lud68dtnay5nc0z29cwq6", + "principal": { + "amount": "500000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1267394", + "denom": "usdx" + }, + "collateral": { + "amount": "2159823000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "355", + "owner": "kava12yakv78pyls0axh5lnhaha6sk6azt29jj7jg46", + "principal": { + "amount": "230291182", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "7442", + "denom": "usdx" + }, + "collateral": { + "amount": "116515577", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "356", + "owner": "kava1p2d5tqngkf0xmmaut5t3lvnwxk8r3jkesq4nav", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "104615", + "denom": "usdx" + }, + "collateral": { + "amount": "260136988", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:43.897016316Z", + "id": "357", + "owner": "kava16jug37mdmzmntrza48z6munagftushdncmx0ll", + "principal": { + "amount": "24640372", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "67382", + "denom": "usdx" + }, + "collateral": { + "amount": "72854000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "359", + "owner": "kava1szqdxulk2n8gy0wcf5k0gpxv6g9xfw7hq8gatx", + "principal": { + "amount": "10000130", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "75322", + "denom": "usdx" + }, + "collateral": { + "amount": "1900000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "360", + "owner": "kava1daexlmcw6ef6v350pj65wgwd6d2s04t9krzhh6", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "40476", + "denom": "usdx" + }, + "collateral": { + "amount": "104667426", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:00:44.590106804Z", + "id": "361", + "owner": "kava1zpcj88j42nyfj4xett8lwdmvxwnlhljny9wcl8", + "principal": { + "amount": "11244169", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3147640", + "denom": "usdx" + }, + "collateral": { + "amount": "4999861500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "363", + "owner": "kava1zwkkhamrvr8fhr3e6cq7e9w56zm2g6d9qljqr7", + "principal": { + "amount": "533077721", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "18915", + "denom": "usdx" + }, + "collateral": { + "amount": "1073384000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:58:31.264015933Z", + "id": "364", + "owner": "kava1u30dpd3h8mdwudrhlfj5uhwhpzlzq4z9k28e4a", + "principal": { + "amount": "10826291", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "60076", + "denom": "usdx" + }, + "collateral": { + "amount": "999999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:02:59.644377189Z", + "id": "366", + "owner": "kava13g63wevgyyvrgyjsuwqj3274aejh6kxruz50qg", + "principal": { + "amount": "16057802", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "5084", + "denom": "usdx" + }, + "collateral": { + "amount": "171209890", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:50.815581672Z", + "id": "367", + "owner": "kava1rldss49zjtc94a7nwn9y2pf7lnqr0c0lg8vhzr", + "principal": { + "amount": "10698601", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "4182548", + "denom": "usdx" + }, + "collateral": { + "amount": "16825426911", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "368", + "owner": "kava1p9fswn29klzkp5vws0mje2g4f4xdln55krv5vt", + "principal": { + "amount": "1673815348", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "69697", + "denom": "usdx" + }, + "collateral": { + "amount": "1000000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:36.983876875Z", + "id": "370", + "owner": "kava1rytcgddazyzeytaumugwtmldfz7dzym3w8fuls", + "principal": { + "amount": "36943452", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "316603", + "denom": "usdx" + }, + "collateral": { + "amount": "408998000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:50.915130002Z", + "id": "371", + "owner": "kava1zpxyy68uxylkdf25ap3cp0jc398xlxg0yj23kr", + "principal": { + "amount": "44064599", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3212", + "denom": "usdx" + }, + "collateral": { + "amount": "56349766", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:55.262259649Z", + "id": "372", + "owner": "kava1hezl6xwva28xt0hk204dllalagenmfsn32w82d", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "7140", + "denom": "usdx" + }, + "collateral": { + "amount": "84697000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:02:25.358186006Z", + "id": "373", + "owner": "kava1wdxsukxg0h2x7sgjcw23ahcn34sesv9k0m225u", + "principal": { + "amount": "10518630", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "426055", + "denom": "usdx" + }, + "collateral": { + "amount": "548999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "375", + "owner": "kava15j9e4gffh6r98vsukd9zt5q2w8wtynfm3qx7qr", + "principal": { + "amount": "59148017", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "74747", + "denom": "usdx" + }, + "collateral": { + "amount": "190000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "376", + "owner": "kava1vp35dt2p5y8tsnptdqdcyypzrmsnjgaq3k3e8g", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "234465", + "denom": "usdx" + }, + "collateral": { + "amount": "898890000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:36.711042819Z", + "id": "377", + "owner": "kava190qjfrpwwvtkhmj4tefz86y2mx94yqgezkpdkx", + "principal": { + "amount": "51916453", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "551697", + "denom": "usdx" + }, + "collateral": { + "amount": "999961500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:14.400991279Z", + "id": "378", + "owner": "kava1e228zg7qfcqed5c78z96rne0fee4f0xdkfhwjq", + "principal": { + "amount": "77740673", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "74697", + "denom": "usdx" + }, + "collateral": { + "amount": "119924000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "379", + "owner": "kava1djun9vdmqhay9llr3pl60pg8rfxamr2z4xlu68", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "553090", + "denom": "usdx" + }, + "collateral": { + "amount": "999961500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:36.711042819Z", + "id": "380", + "owner": "kava1wwne8dzzdz4jjcjp2cmr4vwdqyhanqptrwm5lc", + "principal": { + "amount": "110273637", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2522", + "denom": "usdx" + }, + "collateral": { + "amount": "56893201", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:55.262259649Z", + "id": "381", + "owner": "kava1w0ukaj52gcqeyudwrt0842c36syjzp79fza4wy", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2167589", + "denom": "usdx" + }, + "collateral": { + "amount": "2835741068", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "382", + "owner": "kava1267c4ask3llkjny5876hc8qc4aasvxqxuje0kl", + "principal": { + "amount": "307669304", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "72452", + "denom": "usdx" + }, + "collateral": { + "amount": "2428242815", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:00:01.347323184Z", + "id": "384", + "owner": "kava1myy3lkcshgmg5ke7gj07mmsyuxf3wyazastnpl", + "principal": { + "amount": "10292722", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "44402", + "denom": "usdx" + }, + "collateral": { + "amount": "156294301", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "386", + "owner": "kava138kzn55zekj6hydq5sqt53m2p2u479p6een8pd", + "principal": { + "amount": "11276091", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "8928", + "denom": "usdx" + }, + "collateral": { + "amount": "230151411", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:05.765073985Z", + "id": "387", + "owner": "kava183c3dft0zj5kqnvdxke4cdlt5qa8j47wxt0qd2", + "principal": { + "amount": "21526749", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "124036801", + "denom": "usdx" + }, + "collateral": { + "amount": "149999923000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "390", + "owner": "kava1hnugk43fax68hp6csqymsjc9fpdvl6fn8mgr4y", + "principal": { + "amount": "16756498494", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "917", + "denom": "usdx" + }, + "collateral": { + "amount": "67098716", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:02:25.358186006Z", + "id": "391", + "owner": "kava1pmqrsde4l4t0pyxyn28uquk9e0ea83u0fa3t3r", + "principal": { + "amount": "10075926", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2733517", + "denom": "usdx" + }, + "collateral": { + "amount": "5099761500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "393", + "owner": "kava120hwpwxj22v4p4ehav96dkvl3sn5fcaqy04n2k", + "principal": { + "amount": "395506053", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "167318", + "denom": "usdx" + }, + "collateral": { + "amount": "7326829987", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "394", + "owner": "kava1gnnxpwfht60gvttrs0kfh7qru49nqtyqnudnqw", + "principal": { + "amount": "908154000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "426132", + "denom": "usdx" + }, + "collateral": { + "amount": "545762958", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "396", + "owner": "kava1wuvxx8zeft7g88nazgjd4800fzuxhrm2rqs55x", + "principal": { + "amount": "60231746", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "87417", + "denom": "usdx" + }, + "collateral": { + "amount": "162468718", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:03:36.027198424Z", + "id": "397", + "owner": "kava1yp45n64cj059m55cpl5et3vl46h993a60g5jds", + "principal": { + "amount": "11822273", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "4680405", + "denom": "usdx" + }, + "collateral": { + "amount": "8479261500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "398", + "owner": "kava1932gg48nkx0m5294gswdru76rvwwxfuj2s2cxx", + "principal": { + "amount": "663917696", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "489497", + "denom": "usdx" + }, + "collateral": { + "amount": "44899999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "399", + "owner": "kava1zjw5ndqh6qkrld5f48w9l74ylftapfwudz5a3m", + "principal": { + "amount": "7305866178", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "204266", + "denom": "usdx" + }, + "collateral": { + "amount": "254907989", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:50.815581672Z", + "id": "400", + "owner": "kava1wszz0ym34kstc66cn23jkpp5d27v64y0hjep05", + "principal": { + "amount": "32222000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "54309", + "denom": "usdx" + }, + "collateral": { + "amount": "190000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:09.136574316Z", + "id": "401", + "owner": "kava13jsjaj9mgu8ld9795udsmwtq2z6w880la8pjgk", + "principal": { + "amount": "10331598", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "73832", + "denom": "usdx" + }, + "collateral": { + "amount": "500000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "402", + "owner": "kava193zlfqknqhsxsvwerghyhaak57vqxc85c4an75", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2573368", + "denom": "usdx" + }, + "collateral": { + "amount": "9039810000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "403", + "owner": "kava1vc4jkya3ngzr8nm9g0pqjq245zyedtdns2wgjl", + "principal": { + "amount": "581805346", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "28938", + "denom": "usdx" + }, + "collateral": { + "amount": "80638992", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:00:22.713382299Z", + "id": "404", + "owner": "kava1wgsaae4xsxwxwt6tdzlrecfh4ryv7pgg8sq62c", + "principal": { + "amount": "10235879", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "348788", + "denom": "usdx" + }, + "collateral": { + "amount": "2000000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "405", + "owner": "kava1346xxrjlgks6k4985h56h8nz4g00ywx9sy2fmx", + "principal": { + "amount": "100000890", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "129553", + "denom": "usdx" + }, + "collateral": { + "amount": "15639560000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "407", + "owner": "kava1fj8454k6sm4rjr78u45ls6xyc2hwpt9qmcx70d", + "principal": { + "amount": "2201892538", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "23769", + "denom": "usdx" + }, + "collateral": { + "amount": "1539999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:36.711042819Z", + "id": "408", + "owner": "kava1l8txdnmj888kr9xjzyqrcpwns8wvser6wq63q0", + "principal": { + "amount": "110662450", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "214431", + "denom": "usdx" + }, + "collateral": { + "amount": "300000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:05.765073985Z", + "id": "410", + "owner": "kava1tpwv2a3uqg44axz0wue20ym6wzu2ku256q4wwy", + "principal": { + "amount": "30000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "313415", + "denom": "usdx" + }, + "collateral": { + "amount": "1033961500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:43.897016316Z", + "id": "411", + "owner": "kava1ajxngqkmc05js4m7v54sv3z0ajxn2rxx20vecm", + "principal": { + "amount": "135349212", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "478790", + "denom": "usdx" + }, + "collateral": { + "amount": "500000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "412", + "owner": "kava18dh0mkakhgfp434vnpfl3cumd8ezgj7d8d5thj", + "principal": { + "amount": "69000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "252850", + "denom": "usdx" + }, + "collateral": { + "amount": "338627511", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:55.262259649Z", + "id": "413", + "owner": "kava18smvkrmxz6hz9ue9x37jke3ygkmzsmfvcq7wsk", + "principal": { + "amount": "36253890", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "19667", + "denom": "usdx" + }, + "collateral": { + "amount": "116220000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:34.296774744Z", + "id": "414", + "owner": "kava1scecy0k0d7rda0muu0cgy693fwl39zdsh2jsts", + "principal": { + "amount": "10438358", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "18958", + "denom": "usdx" + }, + "collateral": { + "amount": "364186300", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:05.765073985Z", + "id": "415", + "owner": "kava1yjy9vjm7p6cwtcefm7haf0czawrz0x8tajswt4", + "principal": { + "amount": "25306564", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "17804", + "denom": "usdx" + }, + "collateral": { + "amount": "2933574070", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "417", + "owner": "kava19kncpd7la86z27snj6996u3ds5mtcmc5n864vx", + "principal": { + "amount": "440377862", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "71638", + "denom": "usdx" + }, + "collateral": { + "amount": "52289147", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "418", + "owner": "kava1vdnqddartdwjexhddpmxtv5exc74gnsk56qp48", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "7446808", + "denom": "usdx" + }, + "collateral": { + "amount": "11225766569", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "419", + "owner": "kava184jc94y8canrz64cqwa8qpfgtjfkgasng4lfkc", + "principal": { + "amount": "1724446530", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1101641", + "denom": "usdx" + }, + "collateral": { + "amount": "2190150087", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "420", + "owner": "kava1cxemt79nuwgsmx6lem49dk2l4tpqgtnzngvsw8", + "principal": { + "amount": "168302448", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "19192689", + "denom": "usdx" + }, + "collateral": { + "amount": "25190971629", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "421", + "owner": "kava1hrgp4sumhxcav5gs3xepa9h2pxg0lm74af88pa", + "principal": { + "amount": "2710126178", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3246722", + "denom": "usdx" + }, + "collateral": { + "amount": "4349761500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "422", + "owner": "kava1n7tqawsk5fsc85cx74s96f9gpvhjklmp2rd35t", + "principal": { + "amount": "484965041", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "11873341", + "denom": "usdx" + }, + "collateral": { + "amount": "23999999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "424", + "owner": "kava1jr68259ur9fk0rpsjqgdc2yu92ktxjznkhkzkp", + "principal": { + "amount": "3146802911", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "526479", + "denom": "usdx" + }, + "collateral": { + "amount": "999861500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:14.400991279Z", + "id": "426", + "owner": "kava1gqgnuyzz5w03wjul2cmsk4lgh7ysz300rtyqv2", + "principal": { + "amount": "77313623", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "341535", + "denom": "usdx" + }, + "collateral": { + "amount": "650000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "428", + "owner": "kava15njsc4lap2h94xum2xatf9xmex4088u9wd0u6z", + "principal": { + "amount": "50000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "576", + "denom": "usdx" + }, + "collateral": { + "amount": "58000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:03:52.213324724Z", + "id": "429", + "owner": "kava1pqdfq0c8ul2ud570fkgurv0e0kkyun4njcu908", + "principal": { + "amount": "10072206", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "71272", + "denom": "usdx" + }, + "collateral": { + "amount": "420000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "430", + "owner": "kava1k3njlxztcptmr8g9s3hasw9r6ljje3z2jmg5e0", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "49586", + "denom": "usdx" + }, + "collateral": { + "amount": "101138000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "431", + "owner": "kava1mkqjs4q5udknncq0804npdl6ft0955faf6dlkw", + "principal": { + "amount": "12006852", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "71222", + "denom": "usdx" + }, + "collateral": { + "amount": "98924250", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "432", + "owner": "kava14n3j3lk8qv9l7qaezhk9tvxaxxenv8fe5ljkjq", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "56498512", + "denom": "usdx" + }, + "collateral": { + "amount": "110109408500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "435", + "owner": "kava1egg63hrypuyt2lt9a4n5djd9pm6map27rwwfze", + "principal": { + "amount": "8244440222", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "40345", + "denom": "usdx" + }, + "collateral": { + "amount": "208961500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:05.765073985Z", + "id": "436", + "owner": "kava1gtk0jkrhkah3v89tyl4uju9pfxaqf6x7k37jx2", + "principal": { + "amount": "17823222", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "538729", + "denom": "usdx" + }, + "collateral": { + "amount": "800000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:27.75505786Z", + "id": "437", + "owner": "kava1uywh7xykpca22jqwpx2y04a6gvf8xkc7slggrj", + "principal": { + "amount": "80000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "6431", + "denom": "usdx" + }, + "collateral": { + "amount": "100000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:20.453076633Z", + "id": "438", + "owner": "kava18khx7upj3m2wx5csg974saseneg0yhdljz58e4", + "principal": { + "amount": "13145063", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "71555", + "denom": "usdx" + }, + "collateral": { + "amount": "199999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "440", + "owner": "kava1ljfxurrts4m0prurlvgvmu9y5yxmf9s0tewuyw", + "principal": { + "amount": "10344851", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "379010", + "denom": "usdx" + }, + "collateral": { + "amount": "749980750", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:50.815581672Z", + "id": "441", + "owner": "kava1zzz79tppy6ymqh6cqcs9sghjmfc8l2sex36yhy", + "principal": { + "amount": "56656045", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "222470", + "denom": "usdx" + }, + "collateral": { + "amount": "377999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:28.231878135Z", + "id": "442", + "owner": "kava1p6ukkxqy46dv88cw5cwruj3e26cywq4w8wdw57", + "principal": { + "amount": "32000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "19606", + "denom": "usdx" + }, + "collateral": { + "amount": "107369000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:58:31.264015933Z", + "id": "443", + "owner": "kava1gv4w4epka7hk9yrhjg36952hjpvxl66xk5tunc", + "principal": { + "amount": "10168803", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "55670", + "denom": "usdx" + }, + "collateral": { + "amount": "201180000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:02:09.942783911Z", + "id": "444", + "owner": "kava1tqzyvc705vxc7wxzkvaj4h4kmy0laqltkr4ccu", + "principal": { + "amount": "11982831", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "562088", + "denom": "usdx" + }, + "collateral": { + "amount": "5642037815", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "445", + "owner": "kava1sy2gskxervkfv7ug33e78ty7hmg579w3n67gnr", + "principal": { + "amount": "648626210", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "39657192", + "denom": "usdx" + }, + "collateral": { + "amount": "46124894121", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "448", + "owner": "kava175nsnv7cgf23zczudp62avveqdstkaenlhmdkv", + "principal": { + "amount": "6850000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2871032", + "denom": "usdx" + }, + "collateral": { + "amount": "520207013074", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "449", + "owner": "kava15w26ypf03ew40s2rlpvz6w6zewjllux2nd9zh6", + "principal": { + "amount": "84030265638", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "43871", + "denom": "usdx" + }, + "collateral": { + "amount": "119119000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "450", + "owner": "kava1yc7r3qfqxlds6aw6p9egy42vn8n8wu5hd0ksvm", + "principal": { + "amount": "10000674", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1388779", + "denom": "usdx" + }, + "collateral": { + "amount": "2696108986", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "453", + "owner": "kava1egckau5qukmpuvkz9f8e8dk3z47jc3tz5xhfnn", + "principal": { + "amount": "229163571", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "653401", + "denom": "usdx" + }, + "collateral": { + "amount": "5199999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "455", + "owner": "kava1p5j4vfecg4afhvy04lc43kr8xwe3lg8awpr6tu", + "principal": { + "amount": "100000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "981", + "denom": "usdx" + }, + "collateral": { + "amount": "94567858", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:03:59.168880771Z", + "id": "456", + "owner": "kava10l4pyd0u4k4lrjkuykepkek9r6rnsmw96w70cv", + "principal": { + "amount": "11592577", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "70442", + "denom": "usdx" + }, + "collateral": { + "amount": "280000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "457", + "owner": "kava1ggcxyngdy2zk5ef3spxkyk0lavfxx4yhvx50gp", + "principal": { + "amount": "10000020", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "46168", + "denom": "usdx" + }, + "collateral": { + "amount": "84746000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "458", + "owner": "kava1vcrz5geulv3gywlmv22vvdd57dgxwu9qtq2wv7", + "principal": { + "amount": "10004055", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "51736", + "denom": "usdx" + }, + "collateral": { + "amount": "99999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:02:09.942783911Z", + "id": "459", + "owner": "kava1kfm0ap7dj70g84tnm6t7sv9e07alv40sswlp26", + "principal": { + "amount": "10127040", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "217325", + "denom": "usdx" + }, + "collateral": { + "amount": "599999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:50.915130002Z", + "id": "460", + "owner": "kava1qhjahz8wcd2v45vhqguftxzdcmevmqult0cr6q", + "principal": { + "amount": "66938914", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "37278", + "denom": "usdx" + }, + "collateral": { + "amount": "161916690", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "461", + "owner": "kava14me2jfmcxrvt0wc3yrthaa0wyajunjuvdhqdgw", + "principal": { + "amount": "10000005", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1405", + "denom": "usdx" + }, + "collateral": { + "amount": "600000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:02:41.472293663Z", + "id": "462", + "owner": "kava1r6863cfuphfqn9e8csrh5nwt478hqys0m55jev", + "principal": { + "amount": "19549091", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "70207", + "denom": "usdx" + }, + "collateral": { + "amount": "278673000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "464", + "owner": "kava1q9f35kmf3nmkh8njf504wa9f8xlf5xk730hyaw", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "33513", + "denom": "usdx" + }, + "collateral": { + "amount": "75545000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:59:44.393525543Z", + "id": "465", + "owner": "kava1hj482tmy0tgmtvu75t9j0plmaqn2xm0vy5v6r2", + "principal": { + "amount": "10013543", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "70032", + "denom": "usdx" + }, + "collateral": { + "amount": "708603424", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "467", + "owner": "kava1h664863rtt9hs2ty2vrdslvsa4s253zt08vkjk", + "principal": { + "amount": "10000190", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "83730", + "denom": "usdx" + }, + "collateral": { + "amount": "399908995", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "469", + "owner": "kava18ctftdnzf5npek5lgjsdnv89yzgmcur5vmm4kt", + "principal": { + "amount": "12000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "73907", + "denom": "usdx" + }, + "collateral": { + "amount": "200000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:03:08.223718604Z", + "id": "470", + "owner": "kava1v5amsvjqkj9jhgt524qfwzkgqpppxrjwhqxsn5", + "principal": { + "amount": "15954278", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "4307", + "denom": "usdx" + }, + "collateral": { + "amount": "111855575", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "472", + "owner": "kava1czsgyezfdngjncz722fd5h7erpk6rg9hxr46kv", + "principal": { + "amount": "10000474", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "4891", + "denom": "usdx" + }, + "collateral": { + "amount": "503345144", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "473", + "owner": "kava17a9ac5ehxuaskms96pht653xc8n8geyln5t04g", + "principal": { + "amount": "77021235", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "51411", + "denom": "usdx" + }, + "collateral": { + "amount": "160000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:02:09.942783911Z", + "id": "474", + "owner": "kava1jyackhsdvgltkwuanh86zj2eyctyqxpfp5jlpz", + "principal": { + "amount": "10024467", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2613967", + "denom": "usdx" + }, + "collateral": { + "amount": "5405751556", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "475", + "owner": "kava1yzy4ynjw3047m3pn0kmawc3hrwq0tk5aggurf6", + "principal": { + "amount": "569143267", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1482", + "denom": "usdx" + }, + "collateral": { + "amount": "99810345", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:59:21.832566067Z", + "id": "476", + "owner": "kava152jmxqetd54qy0twfw986xmqc8z55e8lek6jln", + "principal": { + "amount": "10607716", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "539590", + "denom": "usdx" + }, + "collateral": { + "amount": "900000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "477", + "owner": "kava1munszk8x4te0h94wag7qfqa02hzk5c9jy25qlr", + "principal": { + "amount": "130000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "89676", + "denom": "usdx" + }, + "collateral": { + "amount": "2055177425", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "479", + "owner": "kava1qs9h8xtdvdzxr9xn0d43f6xmp8z0af4l3kxu2n", + "principal": { + "amount": "283787387", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "97977", + "denom": "usdx" + }, + "collateral": { + "amount": "2118498000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:11.309262057Z", + "id": "480", + "owner": "kava10fm5uqusl69y7tz0lzzwa28u0aht0keshyyxr4", + "principal": { + "amount": "17644608", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2277858", + "denom": "usdx" + }, + "collateral": { + "amount": "377334585500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "481", + "owner": "kava1v24lr93py37rgqf8nf99nay3letx5dtv4jnpn4", + "principal": { + "amount": "39392980748", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "202961", + "denom": "usdx" + }, + "collateral": { + "amount": "249999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:05.765073985Z", + "id": "482", + "owner": "kava19h4c5a5ma0ldhwynzgnefvjx8003532y3llnuq", + "principal": { + "amount": "30000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "22544977", + "denom": "usdx" + }, + "collateral": { + "amount": "48809998001", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "483", + "owner": "kava1qvsus5qg8yhre7k2c78xkkw4nvqqgev7ezrja8", + "principal": { + "amount": "3515000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "50817", + "denom": "usdx" + }, + "collateral": { + "amount": "2399997000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:58:31.264015933Z", + "id": "484", + "owner": "kava104v3e5ydyszf6t0k5hsgcqw2hhpvekvj8xdu4p", + "principal": { + "amount": "10815529", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "44296", + "denom": "usdx" + }, + "collateral": { + "amount": "72475070", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:55.262259649Z", + "id": "485", + "owner": "kava1xavpqv7s3thhlyn4t7n7mlfrgs52yyw50dyvj2", + "principal": { + "amount": "10064242", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1546", + "denom": "usdx" + }, + "collateral": { + "amount": "99999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:02:25.358186006Z", + "id": "486", + "owner": "kava1cmw28jgmz678srf67u58kvtcqfqe96xhz4utu6", + "principal": { + "amount": "10071931", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "68990", + "denom": "usdx" + }, + "collateral": { + "amount": "4311353945", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:36.711042819Z", + "id": "487", + "owner": "kava1w6wpqtr33cqqspwff6wjrn3ppx083upn383fr4", + "principal": { + "amount": "12130516", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "46628", + "denom": "usdx" + }, + "collateral": { + "amount": "73130540", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "489", + "owner": "kava1tuldyjrm4njrzqhcqr9dwc49n6qmmy3yf7rwm9", + "principal": { + "amount": "10000074", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "79738", + "denom": "usdx" + }, + "collateral": { + "amount": "399961500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:05.765073985Z", + "id": "490", + "owner": "kava1lyhy6urjpcw7j39ms5zsdjfc8ceks0rtketuu7", + "principal": { + "amount": "30000270", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "209821187", + "denom": "usdx" + }, + "collateral": { + "amount": "535399999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "493", + "owner": "kava1f987vmkptm4erfr4pkxz7em2dqv9levu788n3s", + "principal": { + "amount": "40000000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3403", + "denom": "usdx" + }, + "collateral": { + "amount": "100097000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:43.739056413Z", + "id": "494", + "owner": "kava16exxhy0llf80mke2kue7rpvd0tydzel67mr5gz", + "principal": { + "amount": "10021670", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "251972", + "denom": "usdx" + }, + "collateral": { + "amount": "350000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:14.400991279Z", + "id": "495", + "owner": "kava1ksdwmtj2kvn3ca3p7acmr7a7ke5vf3r3vallqy", + "principal": { + "amount": "38000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "68432", + "denom": "usdx" + }, + "collateral": { + "amount": "138431097", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "497", + "owner": "kava16nkl3flcdm26hsza5q8zlgqpqtntems6ua0yxh", + "principal": { + "amount": "10000550", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "39356", + "denom": "usdx" + }, + "collateral": { + "amount": "229948554", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:31.545909484Z", + "id": "500", + "owner": "kava1afjd6f4ucljlsqd8srkhcph6h9su9xr28gnlej", + "principal": { + "amount": "22498006", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "44481", + "denom": "usdx" + }, + "collateral": { + "amount": "204788332", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:31.545909484Z", + "id": "503", + "owner": "kava1pzsjduk42le33zyjrlch7uged7f8n5zcaf2kdv", + "principal": { + "amount": "10789468", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "54363", + "denom": "usdx" + }, + "collateral": { + "amount": "143087090", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:28.231878135Z", + "id": "506", + "owner": "kava1q0pv87dmzwldqjvepd60xlny9q9xajd6x4sga5", + "principal": { + "amount": "12316574", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "68062", + "denom": "usdx" + }, + "collateral": { + "amount": "109861500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "507", + "owner": "kava1ve5h4gdygeh7cyssflpel6xht5hrzpw0yc9akj", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "6557", + "denom": "usdx" + }, + "collateral": { + "amount": "89961500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "508", + "owner": "kava17shza044el9zejk7hd5wqcm85sankrcr3pjshv", + "principal": { + "amount": "10000081", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "142608", + "denom": "usdx" + }, + "collateral": { + "amount": "5103611500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "510", + "owner": "kava1famggza0sju5964gls45pmz2662fluwst53xq3", + "principal": { + "amount": "623899956", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "102447", + "denom": "usdx" + }, + "collateral": { + "amount": "2965833131", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "511", + "owner": "kava164t922sdhpchajlvydywt3wdsd0tt3k5zp9lql", + "principal": { + "amount": "307979003", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "17390379", + "denom": "usdx" + }, + "collateral": { + "amount": "1162399471000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "512", + "owner": "kava15fu6ehw756hd3dyvws0xfwmrugfz8m6f5n030l", + "principal": { + "amount": "140010045689", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "42551", + "denom": "usdx" + }, + "collateral": { + "amount": "100706134", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:55.262259649Z", + "id": "513", + "owner": "kava1jgh5t0nmuhq4ujay6wtth7yzpdvzqqsqdue8s7", + "principal": { + "amount": "10056638", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "4594305", + "denom": "usdx" + }, + "collateral": { + "amount": "15203754344", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "514", + "owner": "kava1arvsc39ytsu7tx8fhtx2c9l2naqgzhgwpce2zj", + "principal": { + "amount": "2072694986", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "67502", + "denom": "usdx" + }, + "collateral": { + "amount": "99920000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "518", + "owner": "kava1fffdmzjvzvem2v9ac4a223uc477rev77r5yypg", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "135200", + "denom": "usdx" + }, + "collateral": { + "amount": "199961500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:03:36.027198424Z", + "id": "527", + "owner": "kava14fnf4afrj60tcv4gc2w5jvhfyq6dered64c7g4", + "principal": { + "amount": "20403404", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "6862916", + "denom": "usdx" + }, + "collateral": { + "amount": "10222401459", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "529", + "owner": "kava1f2q535jw6z4c590apll5j77kdm7ka0qzwksvru", + "principal": { + "amount": "1197790857", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1528901", + "denom": "usdx" + }, + "collateral": { + "amount": "4211962937", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "530", + "owner": "kava1utp56q3kn8e8yn0ndsw8n6wef2yqg5umtuywy8", + "principal": { + "amount": "367673908", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "43913", + "denom": "usdx" + }, + "collateral": { + "amount": "152894876", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "532", + "owner": "kava1gyynypgz03qq9jdf0u7y3w8uuw9ey3lksjn0nc", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "517327", + "denom": "usdx" + }, + "collateral": { + "amount": "1544009070", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "534", + "owner": "kava1u84mr5ndzx29q0pxvv9zyqq0wcth780hycrt0m", + "principal": { + "amount": "145078599", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "45293627", + "denom": "usdx" + }, + "collateral": { + "amount": "89999723000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "537", + "owner": "kava1pmkn0rn07yqcfq0x2za5s3hvecufve3qttwfmw", + "principal": { + "amount": "6796712904", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "103144", + "denom": "usdx" + }, + "collateral": { + "amount": "248701778", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:11.309262057Z", + "id": "538", + "owner": "kava1fzemz4j2tzrxah9r9fpdecdz46f04mlkhaj3fw", + "principal": { + "amount": "29269014", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "66576", + "denom": "usdx" + }, + "collateral": { + "amount": "200000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "539", + "owner": "kava1s0sng9l2espfdu49a25d4r0ewjd0qjkj42jm49", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "34862", + "denom": "usdx" + }, + "collateral": { + "amount": "99999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "541", + "owner": "kava120jyzpzu8ugg697zg7z5a4epfh0dxt44xtx930", + "principal": { + "amount": "10002240", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "47948", + "denom": "usdx" + }, + "collateral": { + "amount": "149584500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:50.915130002Z", + "id": "542", + "owner": "kava1p9zta57w420jqh6y24az869nufzzcf25a3w6w3", + "principal": { + "amount": "10254209", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "66392", + "denom": "usdx" + }, + "collateral": { + "amount": "82740000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "544", + "owner": "kava1pd79wry4m8xqcr8nu66uz0j9qxkh6v7af9w9yx", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "169694", + "denom": "usdx" + }, + "collateral": { + "amount": "362447000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:36.983876875Z", + "id": "545", + "owner": "kava1kt4ss0ewq2u0yuqlmqx2ky3f5a96sj4adzpghp", + "principal": { + "amount": "33108141", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "664721", + "denom": "usdx" + }, + "collateral": { + "amount": "9973286751", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "546", + "owner": "kava155wzd5qzxs2wc58gw2czxy57k6cf6lpl4dphha", + "principal": { + "amount": "1355787790", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1580266", + "denom": "usdx" + }, + "collateral": { + "amount": "3412923000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "548", + "owner": "kava17j57lk8cx7ndfyekfm6t0aeva2zpsj2scrct9c", + "principal": { + "amount": "374609050", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "8695", + "denom": "usdx" + }, + "collateral": { + "amount": "74136275", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "549", + "owner": "kava1gl0y28ghee428e38ca9y3ges7dw3w6akfldpf2", + "principal": { + "amount": "12008606", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "143523", + "denom": "usdx" + }, + "collateral": { + "amount": "210947990", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:43.739056413Z", + "id": "550", + "owner": "kava1agd0k03g4qd6khel3greh9rpfvpwnwnpwwe7nd", + "principal": { + "amount": "26000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "65657", + "denom": "usdx" + }, + "collateral": { + "amount": "99999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "553", + "owner": "kava14pczfzuxj2x5waf7havqh3uzk65psye56u9tpw", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "18359", + "denom": "usdx" + }, + "collateral": { + "amount": "109484500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:09.136574316Z", + "id": "554", + "owner": "kava1q2tzz7g67jkfr40qsmrd3mlc0rcnasc2v5yyqa", + "principal": { + "amount": "10327718", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "178858", + "denom": "usdx" + }, + "collateral": { + "amount": "399908995", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "559", + "owner": "kava1ws3z8cd6zy4sty6m3wezd56v53swr8fpzjs96u", + "principal": { + "amount": "28000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1743", + "denom": "usdx" + }, + "collateral": { + "amount": "649248043", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:58:31.264015933Z", + "id": "561", + "owner": "kava17ltd0q3277h2w6wplqsfxe2l3hj30jaeqg3nf0", + "principal": { + "amount": "10003839", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "70596", + "denom": "usdx" + }, + "collateral": { + "amount": "1999884500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "562", + "owner": "kava10lhnlwlek6yg5n734jn8qukur2kjjhcw09xagl", + "principal": { + "amount": "281011535", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "66319", + "denom": "usdx" + }, + "collateral": { + "amount": "99961500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:05.765073985Z", + "id": "564", + "owner": "kava1dkv7dt5dus66v3qssk3xvejlspqcyjtam5822s", + "principal": { + "amount": "10196752", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "17749", + "denom": "usdx" + }, + "collateral": { + "amount": "199999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:58:07.217776454Z", + "id": "565", + "owner": "kava1wk3cra4t0ma7fmd0lzwt4v0r2zmuw5dac4dgj8", + "principal": { + "amount": "10095233", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "132359", + "denom": "usdx" + }, + "collateral": { + "amount": "199861500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:14.400991279Z", + "id": "567", + "owner": "kava1uyhegc7h4mdc688jrkkqpr3p7wfuwk5kjmqr3q", + "principal": { + "amount": "24161835", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "64146", + "denom": "usdx" + }, + "collateral": { + "amount": "100000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "570", + "owner": "kava1a55mtutup4gsefhlgl2eyquqvddhcthajj7hyl", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "61555", + "denom": "usdx" + }, + "collateral": { + "amount": "101950000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:02:09.942783911Z", + "id": "571", + "owner": "kava1d75drw4t90c8u4cpnrj5skt9dptd8ndq5pfnfg", + "principal": { + "amount": "10128491", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "45903", + "denom": "usdx" + }, + "collateral": { + "amount": "140000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:27.75505786Z", + "id": "573", + "owner": "kava1jy5s2j6m9qe5ctyu528fa527s88xt7vmvlvn9h", + "principal": { + "amount": "10390537", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "18893", + "denom": "usdx" + }, + "collateral": { + "amount": "94108000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "577", + "owner": "kava1lqgw9gczxfrnlyqj3wxcjpe72xlwka8l707t07", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "9981981047", + "denom": "usdx" + }, + "collateral": { + "amount": "24999900000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "584", + "owner": "kava1p3ucd3ptpw902fluyjzhq3ffgq4ntddaysyq8h", + "principal": { + "amount": "1750000000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "61481", + "denom": "usdx" + }, + "collateral": { + "amount": "1268288000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:36.711042819Z", + "id": "585", + "owner": "kava1ym6mnfu60ss26jxe3q4uu3r9q6mm9jhvsd6v42", + "principal": { + "amount": "14015644", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "63571", + "denom": "usdx" + }, + "collateral": { + "amount": "100000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "586", + "owner": "kava1fr7z092tv959sv6ktnqp6hf0gewcepn6rjere7", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "143824", + "denom": "usdx" + }, + "collateral": { + "amount": "519000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:50.915130002Z", + "id": "588", + "owner": "kava1m9fdeu7d96ea6w925cj84573fz9czx0juuj3yk", + "principal": { + "amount": "67206060", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "66256", + "denom": "usdx" + }, + "collateral": { + "amount": "112019000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:00:22.713382299Z", + "id": "590", + "owner": "kava1ph2cglswrvle0yynw8klqvc9xq2g0c79km4vj8", + "principal": { + "amount": "15003210", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "17928088", + "denom": "usdx" + }, + "collateral": { + "amount": "31021777858", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "591", + "owner": "kava1tk26wrslz7kn297uhgavhu4wuqqh63ypueww8e", + "principal": { + "amount": "3995000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "160616", + "denom": "usdx" + }, + "collateral": { + "amount": "711579883", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:36.711042819Z", + "id": "593", + "owner": "kava1x3ppp8k0d3r70wmzk8sjjcwsh7m8lwpskympuq", + "principal": { + "amount": "90000257", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "62854", + "denom": "usdx" + }, + "collateral": { + "amount": "90000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "595", + "owner": "kava1heexugcm6rvxrdhefhesu9z7xfgwpv5p0vdnxq", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "122316", + "denom": "usdx" + }, + "collateral": { + "amount": "293947000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:50.915130002Z", + "id": "598", + "owner": "kava1rgh7rscdgr24ezzdq8qmcqr4ztkye9mz8am7jn", + "principal": { + "amount": "42586245", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "44552", + "denom": "usdx" + }, + "collateral": { + "amount": "108507500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:02:09.942783911Z", + "id": "599", + "owner": "kava1l820ssg03trajf9m90a7ftf8wj4au80f9ysx6j", + "principal": { + "amount": "10033050", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "9237", + "denom": "usdx" + }, + "collateral": { + "amount": "1092945394", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "600", + "owner": "kava183qwnf0k69pt685whvz7pf2aqlc74dks73rljc", + "principal": { + "amount": "150107155", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "105345", + "denom": "usdx" + }, + "collateral": { + "amount": "187656122", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:20.453076633Z", + "id": "601", + "owner": "kava1t2zha9k5ghuw3s03dm4h80u5m0nkrln4mzk45e", + "principal": { + "amount": "17000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "62376", + "denom": "usdx" + }, + "collateral": { + "amount": "100000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "603", + "owner": "kava1lpu4p4wxxqk60awyfsd6wc382kpf87l52n7kan", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1451259", + "denom": "usdx" + }, + "collateral": { + "amount": "2298136499", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "604", + "owner": "kava144ufawnvyjpfpw9cf65jj35jhun7qzl948fw7v", + "principal": { + "amount": "321652159", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "17595", + "denom": "usdx" + }, + "collateral": { + "amount": "100000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "606", + "owner": "kava1c2y4xkxrly9jj7nj5pklukuegenhzyar5l8umf", + "principal": { + "amount": "10000127", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "62182", + "denom": "usdx" + }, + "collateral": { + "amount": "99861500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "608", + "owner": "kava1qahvnv9yypfn3d2jmur3fpz8y6qhw9hvkzespj", + "principal": { + "amount": "10000080", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "4460011", + "denom": "usdx" + }, + "collateral": { + "amount": "10000000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "609", + "owner": "kava1u0keta2qcwd4m6wn48j80nwrsck3d8e9sfzk2w", + "principal": { + "amount": "776316274", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "59674", + "denom": "usdx" + }, + "collateral": { + "amount": "89840000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "611", + "owner": "kava1nmc03lhn9mmazle9rt9dpctrrk7ld3p6pn0sml", + "principal": { + "amount": "10000044", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "304042", + "denom": "usdx" + }, + "collateral": { + "amount": "509925634", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:14.400991279Z", + "id": "613", + "owner": "kava14s6qe2efrxnn686jztajqgauey0wekr3f4vmnt", + "principal": { + "amount": "50655434", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "5102", + "denom": "usdx" + }, + "collateral": { + "amount": "3030585962", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:03:28.737551656Z", + "id": "614", + "owner": "kava1rpmcujjl23d5drt43kssx8m3cdpv2rgssy98cn", + "principal": { + "amount": "11015274", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "164933", + "denom": "usdx" + }, + "collateral": { + "amount": "26776990500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "615", + "owner": "kava1y0rytym5j70wl9cdh39e4myclgdhsctvp8mh7e", + "principal": { + "amount": "3062287576", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1135765", + "denom": "usdx" + }, + "collateral": { + "amount": "2219861500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "616", + "owner": "kava197qyvn22tet77z5mk78ck95g9wmtq3lckrgfzq", + "principal": { + "amount": "210000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1161", + "denom": "usdx" + }, + "collateral": { + "amount": "62314233", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:59:44.393525543Z", + "id": "618", + "owner": "kava1757dx4vjqa7f9tqtvwp3qm4rhwe7rutdz0fup0", + "principal": { + "amount": "10011879", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3397", + "denom": "usdx" + }, + "collateral": { + "amount": "338840360", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "620", + "owner": "kava198z78dq8pgrclfuexjxuxju2evcvg6qvpsftpx", + "principal": { + "amount": "50138731", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "5471904", + "denom": "usdx" + }, + "collateral": { + "amount": "10016683837", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "622", + "owner": "kava19zqpv4s3hm9wa7t3kwsefj56xfu5477mln2gr5", + "principal": { + "amount": "1111332401", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "155470403", + "denom": "usdx" + }, + "collateral": { + "amount": "553291747747", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "624", + "owner": "kava1ldyc7pkjtcy9gd8lul653s40mtalp8904hzt86", + "principal": { + "amount": "60168041758", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "772040", + "denom": "usdx" + }, + "collateral": { + "amount": "2299998000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:43.897016316Z", + "id": "627", + "owner": "kava1ce2d3qlhyw0zymvcmnrpdgt8nlfmt3zxw460yl", + "principal": { + "amount": "136794602", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2820970", + "denom": "usdx" + }, + "collateral": { + "amount": "5000000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "631", + "owner": "kava1hw5j9p9mqtye42rvjqggkxs283spjtx9ns5tnk", + "principal": { + "amount": "600000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "44252", + "denom": "usdx" + }, + "collateral": { + "amount": "149859500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:03:36.027198424Z", + "id": "632", + "owner": "kava1vu905f0043mq5wdry0q8gvlpvu8h4hx4894d76", + "principal": { + "amount": "15528722", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "565519", + "denom": "usdx" + }, + "collateral": { + "amount": "998808462", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "634", + "owner": "kava15nffgda7t668av06vhqz3ypks94gas9kla36aa", + "principal": { + "amount": "100000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "40574", + "denom": "usdx" + }, + "collateral": { + "amount": "149824000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:58:31.264015933Z", + "id": "636", + "owner": "kava1pckx96w35njptwnel9j2eg3ac52ruemepslxcj", + "principal": { + "amount": "11732484", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "34864", + "denom": "usdx" + }, + "collateral": { + "amount": "568858706", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:02:49.66052784Z", + "id": "637", + "owner": "kava1245ydegvlzp0rr3q5a0ejwyr0e2zaejtuv34rj", + "principal": { + "amount": "15378761", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "60906", + "denom": "usdx" + }, + "collateral": { + "amount": "90000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "638", + "owner": "kava1fnsu4x447vqr36lf733x8xyem3ulvktg54gsar", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "60887", + "denom": "usdx" + }, + "collateral": { + "amount": "4999000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "639", + "owner": "kava19cagyd5nu3xalnxlwh29fs9qnwfgv2jc8m4cwd", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "132554", + "denom": "usdx" + }, + "collateral": { + "amount": "227828700", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:36.983876875Z", + "id": "640", + "owner": "kava10fsu58fz5p3pny66t7lx4t07x0aeahgc7dkz0k", + "principal": { + "amount": "22000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1152630", + "denom": "usdx" + }, + "collateral": { + "amount": "2499961500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "641", + "owner": "kava1dt4dsl6tmwa286gaua3edhe2hx8y7f6yag0ycc", + "principal": { + "amount": "255519226", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "288356", + "denom": "usdx" + }, + "collateral": { + "amount": "1099823000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "644", + "owner": "kava1tgwt0fs7ewk5en5f4l0lta96je67qzszs6a9av", + "principal": { + "amount": "50000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "814484", + "denom": "usdx" + }, + "collateral": { + "amount": "120094116321", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "645", + "owner": "kava1060g6qppa3pr079s9skd7h2vzzjshdyd6u93kt", + "principal": { + "amount": "20110546384", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1975165", + "denom": "usdx" + }, + "collateral": { + "amount": "70204605500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "647", + "owner": "kava19mtegk4rd6fjfxjsmknn8862gcmfd32myj7sva", + "principal": { + "amount": "9630085045", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "308917", + "denom": "usdx" + }, + "collateral": { + "amount": "599646000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:36.711042819Z", + "id": "648", + "owner": "kava1t7t6fweerd5azv0rdjqggylg6zj08u5thp2uz4", + "principal": { + "amount": "80805088", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "51439", + "denom": "usdx" + }, + "collateral": { + "amount": "116615233", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "649", + "owner": "kava1wghqx6uq2gr7medxc9s8rsvy39720ecneyren3", + "principal": { + "amount": "10000352", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "432644", + "denom": "usdx" + }, + "collateral": { + "amount": "999684500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:50.815581672Z", + "id": "650", + "owner": "kava15vkeet287q7g379zhjdgp3ljz0x0lsz0glqan7", + "principal": { + "amount": "115564439", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "40800", + "denom": "usdx" + }, + "collateral": { + "amount": "706776294", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "651", + "owner": "kava1etc48067kxc29k0n86pwl3l92vp8fszvsevcm7", + "principal": { + "amount": "76812191", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "53539", + "denom": "usdx" + }, + "collateral": { + "amount": "117406278", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "654", + "owner": "kava1ufhu8zlswufcvu82kqeu0jgclum2psvx453f4p", + "principal": { + "amount": "10002910", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "291968", + "denom": "usdx" + }, + "collateral": { + "amount": "599000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "657", + "owner": "kava1yhp6n6wdf7xevyn2r2z85m0ejrgl3rfe9akmnv", + "principal": { + "amount": "62662477", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "69739347", + "denom": "usdx" + }, + "collateral": { + "amount": "137999584500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "659", + "owner": "kava1pu9g0q0ceduaq0827l0pkyjgejcfn66zg9n0rq", + "principal": { + "amount": "15000000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "58519", + "denom": "usdx" + }, + "collateral": { + "amount": "1009999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "663", + "owner": "kava19t5f34y3m4cy983gdzgm02yjax8utyqy7aexp9", + "principal": { + "amount": "10000025", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3619", + "denom": "usdx" + }, + "collateral": { + "amount": "90157124", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:00:53.396708352Z", + "id": "665", + "owner": "kava1fzzfexc5zzqgpt9jm4vvhuhagvg0m36z2gldl3", + "principal": { + "amount": "10101666", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "70758", + "denom": "usdx" + }, + "collateral": { + "amount": "179860500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:56.067192031Z", + "id": "666", + "owner": "kava1wlzmzdhyyw82ea484lnx4yjrahxstrnrxxxr84", + "principal": { + "amount": "17128376", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "7626", + "denom": "usdx" + }, + "collateral": { + "amount": "159104617", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:05.765073985Z", + "id": "667", + "owner": "kava1nzqt43xzltcnj0ylwn6k5q6d99efhl60l2z5f5", + "principal": { + "amount": "10195238", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "36836964", + "denom": "usdx" + }, + "collateral": { + "amount": "99999997000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "670", + "owner": "kava10ay55dxkrlhy9vdaj6pr9zexwalp6cjtauepvl", + "principal": { + "amount": "11816785995", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1170458", + "denom": "usdx" + }, + "collateral": { + "amount": "3500000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "672", + "owner": "kava16lhwsqujy9tqv38k3d2jwyuqupj7rtwrxwk668", + "principal": { + "amount": "375000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "57934", + "denom": "usdx" + }, + "collateral": { + "amount": "140050000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "673", + "owner": "kava14xkem8rgndu4ptkt7p398c8ujrqgzg9regxcj9", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1523", + "denom": "usdx" + }, + "collateral": { + "amount": "88345156", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:00:08.102456799Z", + "id": "674", + "owner": "kava19eqckwrd77ec0nq64r2c7nzrxvekmd5el7l7x0", + "principal": { + "amount": "11566280", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "56499", + "denom": "usdx" + }, + "collateral": { + "amount": "103340000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:55.262259649Z", + "id": "675", + "owner": "kava1d3uwmaelq8guzryhkttmsjsu676ykw26l2cdzu", + "principal": { + "amount": "10054793", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1079683", + "denom": "usdx" + }, + "collateral": { + "amount": "2495718637", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "679", + "owner": "kava15784n673568qcxc2m9eylnuzdhmnf7jau0hdxk", + "principal": { + "amount": "299543502", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "57209", + "denom": "usdx" + }, + "collateral": { + "amount": "84994651", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "683", + "owner": "kava129h49z4glgh6lrpl5amj9terauw0m2qgmrz0us", + "principal": { + "amount": "10000010", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "60", + "denom": "usdx" + }, + "collateral": { + "amount": "152055509", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:03:08.223718604Z", + "id": "684", + "owner": "kava1w4umquan7w2v3n3enh6ap854vk4a58kftnq4au", + "principal": { + "amount": "23216032", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3182886", + "denom": "usdx" + }, + "collateral": { + "amount": "5940861500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "685", + "owner": "kava1tusm6xvctqahxcwdl3q3v50mw0dnecf6frt6ve", + "principal": { + "amount": "670565982", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1851834", + "denom": "usdx" + }, + "collateral": { + "amount": "27199856500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "688", + "owner": "kava1mwpvqkvyxgf60pqwvr2vxq0yy86f3kqzcpqarr", + "principal": { + "amount": "3014351441", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "429828", + "denom": "usdx" + }, + "collateral": { + "amount": "950000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:36.711042819Z", + "id": "690", + "owner": "kava1fnrfp3clq57pnsa5k2s0k3uxa8ap44sxj43hqh", + "principal": { + "amount": "80117453", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "56399", + "denom": "usdx" + }, + "collateral": { + "amount": "102785791", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "692", + "owner": "kava1ys2eh89ym4gws20z5tyw28a6jufzwwn5dr6x6z", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "53664", + "denom": "usdx" + }, + "collateral": { + "amount": "69240000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "695", + "owner": "kava19w6akrjw4zaeyhnqxaucwyp4mgzffmqfxwelp9", + "principal": { + "amount": "10001721", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "18046", + "denom": "usdx" + }, + "collateral": { + "amount": "65060000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:59:21.832566067Z", + "id": "696", + "owner": "kava1hzmc908kc2a8nmlgrlun4v8742vxmdx9gpz7d3", + "principal": { + "amount": "10267874", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1661", + "denom": "usdx" + }, + "collateral": { + "amount": "2000000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:43.897016316Z", + "id": "699", + "owner": "kava1mx9kvdhwkp8r6qdh7kvj7j640ktg03a9qx26pk", + "principal": { + "amount": "11931042", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "285096", + "denom": "usdx" + }, + "collateral": { + "amount": "1145187581", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "700", + "owner": "kava1vxzg3hwck6hny22pd0j83pv7h7wddj4gmu492c", + "principal": { + "amount": "160051891", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "8523", + "denom": "usdx" + }, + "collateral": { + "amount": "1581306691", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "701", + "owner": "kava126wg3hfgrxspmtupvyqvall5g75xr7fmxdssen", + "principal": { + "amount": "193155517", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1734404", + "denom": "usdx" + }, + "collateral": { + "amount": "35000116000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "702", + "owner": "kava1kfrjwuur93wthdwc6kpf36lwftdzz22wxe5gae", + "principal": { + "amount": "5331672678", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "6626", + "denom": "usdx" + }, + "collateral": { + "amount": "73000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:50.815581672Z", + "id": "704", + "owner": "kava1mgqnw8kwpclxle6n4cc64d5y2k3ma5gqumd9qz", + "principal": { + "amount": "10682069", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "5025", + "denom": "usdx" + }, + "collateral": { + "amount": "71134712", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "707", + "owner": "kava188hqscan94ev9v8l0szekcmuz30gfrc4dcj57v", + "principal": { + "amount": "10004398", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "35531", + "denom": "usdx" + }, + "collateral": { + "amount": "100000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "708", + "owner": "kava1cwwhp433awcth3906j8ljnk0a4986vs4n0ycjn", + "principal": { + "amount": "10082259", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "58721", + "denom": "usdx" + }, + "collateral": { + "amount": "131630000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:34.296774744Z", + "id": "711", + "owner": "kava1vdm7qe7m0ml7lupghyqt94905fwksplwuztcwj", + "principal": { + "amount": "10870724", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1565", + "denom": "usdx" + }, + "collateral": { + "amount": "227369000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:02:41.472293663Z", + "id": "714", + "owner": "kava18u2vtjmcf4788cc3p5htp509zv0la4a3q8ahhd", + "principal": { + "amount": "15602657", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "29020", + "denom": "usdx" + }, + "collateral": { + "amount": "109996000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:45.943099302Z", + "id": "716", + "owner": "kava1xnw3ty56drc6xyeuw4dl3pkj0sscasnmgfra45", + "principal": { + "amount": "12269212", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "60245", + "denom": "usdx" + }, + "collateral": { + "amount": "106112851", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:07.335098476Z", + "id": "717", + "owner": "kava1n0rncp6td9fss6nws05vc7tp7km8lqg26s2cup", + "principal": { + "amount": "14241515", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "5784", + "denom": "usdx" + }, + "collateral": { + "amount": "99150000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:45.943099302Z", + "id": "721", + "owner": "kava1uct77gqud966lrvgm6mawelh4u6dl5ac0a33ve", + "principal": { + "amount": "11028856", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3695", + "denom": "usdx" + }, + "collateral": { + "amount": "60000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:31.545909484Z", + "id": "722", + "owner": "kava1ssvlfv0l580ck33dfrpd9my2mkx72ur66h0zk7", + "principal": { + "amount": "10134519", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1793026", + "denom": "usdx" + }, + "collateral": { + "amount": "3615669408", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "723", + "owner": "kava18crmeclf9lfjv5p56nw5pdwrmnl232u6z2p8r7", + "principal": { + "amount": "350000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1250575", + "denom": "usdx" + }, + "collateral": { + "amount": "2399999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "728", + "owner": "kava1guwwcc8n9e7h66qzus93muh585ckj7qsdz5pfq", + "principal": { + "amount": "250000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "40278", + "denom": "usdx" + }, + "collateral": { + "amount": "129764000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "733", + "owner": "kava1gsn4670rqjcvym2p9dhw8euhl3w2ls7qyfkrpp", + "principal": { + "amount": "19299953", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "34609", + "denom": "usdx" + }, + "collateral": { + "amount": "525000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:36.711042819Z", + "id": "734", + "owner": "kava1p6mdwjhnd0v8vutx8238kndapp77nu66ky4gz5", + "principal": { + "amount": "90000089", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "267222", + "denom": "usdx" + }, + "collateral": { + "amount": "898457085", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:36.711042819Z", + "id": "735", + "owner": "kava1ttrw6gxz9nz49gse9v0tqqa2u97s34yx4shl55", + "principal": { + "amount": "96211372", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "7982", + "denom": "usdx" + }, + "collateral": { + "amount": "113729000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:03:52.213324724Z", + "id": "738", + "owner": "kava1vlpsrmdyuywvaqrv7rx6xga224sqfwz3fyfhwq", + "principal": { + "amount": "13079524", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "46562", + "denom": "usdx" + }, + "collateral": { + "amount": "166401500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:05.765073985Z", + "id": "740", + "owner": "kava1tvz5kalehzrmn0n3xvpeauvuvvcjar5vl23nny", + "principal": { + "amount": "10183893", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "14906", + "denom": "usdx" + }, + "collateral": { + "amount": "25061161959", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "741", + "owner": "kava1up858ehlg5gsdfx068z42tmmjequky8cn5jzq3", + "principal": { + "amount": "4302105257", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "53329", + "denom": "usdx" + }, + "collateral": { + "amount": "100000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "743", + "owner": "kava16cxqgr30zvfktmupsk4yp4j6kkwmva2nj4rumh", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "248993", + "denom": "usdx" + }, + "collateral": { + "amount": "499999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "746", + "owner": "kava1u7arfjp9pqhel7lpg2xlpm8yd3wsa7qdgvps47", + "principal": { + "amount": "50081291", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "44097", + "denom": "usdx" + }, + "collateral": { + "amount": "137739000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "747", + "owner": "kava1xyvekep7vx8lklmeframd67nsc2mvgajl56qd7", + "principal": { + "amount": "10069352", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "64087", + "denom": "usdx" + }, + "collateral": { + "amount": "2845998000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "748", + "owner": "kava1lynr3f7zqhpcwacvatewcwj0ar5q9sgx7tesj4", + "principal": { + "amount": "343363229", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "9684", + "denom": "usdx" + }, + "collateral": { + "amount": "93107606", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "751", + "owner": "kava154ffftam7vp9u623fyag968qty4xdglj8nttqa", + "principal": { + "amount": "10000484", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "5600", + "denom": "usdx" + }, + "collateral": { + "amount": "86578132", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:57:13.731216849Z", + "id": "752", + "owner": "kava1mdzaz23a879hc33c8z9m5wqxyky060ylsqtxhp", + "principal": { + "amount": "10041025", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "666555", + "denom": "usdx" + }, + "collateral": { + "amount": "1480802919", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "756", + "owner": "kava18d0er3p3esg4t0xq8nlsd568p2xh5l2rw864k0", + "principal": { + "amount": "151934144", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "43480", + "denom": "usdx" + }, + "collateral": { + "amount": "82061500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:59:44.393525543Z", + "id": "757", + "owner": "kava1rmv7pfh2cn2vuzdxffq8ar8zjarjuaj05wfydq", + "principal": { + "amount": "10011649", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "43995", + "denom": "usdx" + }, + "collateral": { + "amount": "88651500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:18.15526764Z", + "id": "759", + "owner": "kava1u87kxuwtcvzvfnmnv4xrxdz9e02uxw3vmu0rj0", + "principal": { + "amount": "10311633", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "44563", + "denom": "usdx" + }, + "collateral": { + "amount": "150000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:59:21.832566067Z", + "id": "761", + "owner": "kava1cfm868f9tyxuc8nhwht8uskdskcspukn2yhwfy", + "principal": { + "amount": "10270883", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "481529", + "denom": "usdx" + }, + "collateral": { + "amount": "1119961500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "762", + "owner": "kava1sqj3mx9ldpfdrl648gkgk97kt9vdgtpr8h54d4", + "principal": { + "amount": "100057620", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "51959", + "denom": "usdx" + }, + "collateral": { + "amount": "102329000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "764", + "owner": "kava1pswe4zg8agsn8vjqtp5y7p69c2uu9znc0jxmm6", + "principal": { + "amount": "10000060", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "49331", + "denom": "usdx" + }, + "collateral": { + "amount": "88169571", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:36.711042819Z", + "id": "766", + "owner": "kava1mmstl7fvtlgsp2n7kfrnww8ec83f0tmhvgc4cp", + "principal": { + "amount": "14000141", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "11160", + "denom": "usdx" + }, + "collateral": { + "amount": "2000000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "770", + "owner": "kava18tmucr5zne0gl0qrflzj4j2p03vfrqqtmc7zu8", + "principal": { + "amount": "199992616", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "243698", + "denom": "usdx" + }, + "collateral": { + "amount": "25109997000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "774", + "owner": "kava1dkd54gp23afg7hlrczhpfr4rmgduqyfujgheg8", + "principal": { + "amount": "3578032637", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "646461", + "denom": "usdx" + }, + "collateral": { + "amount": "1686459900", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "776", + "owner": "kava1kyeqkawhfxjk34ce53lyx7z2akj495x3fe7nh2", + "principal": { + "amount": "138464541", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "4329910", + "denom": "usdx" + }, + "collateral": { + "amount": "10000535500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "777", + "owner": "kava1delejz0pfradzear7rtx2gd5nvxyu97kvjhmuy", + "principal": { + "amount": "1027510443", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "35094", + "denom": "usdx" + }, + "collateral": { + "amount": "98999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:00:53.396708352Z", + "id": "778", + "owner": "kava1rgtrf3nluqls6q3z6snyytzgtsf29d0eu4m4gu", + "principal": { + "amount": "10104704", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "109899", + "denom": "usdx" + }, + "collateral": { + "amount": "400061500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:43.897016316Z", + "id": "780", + "owner": "kava1hzegeqztewllls8xldpeuje5xtnuehmdqjfa4n", + "principal": { + "amount": "49281646", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "89451", + "denom": "usdx" + }, + "collateral": { + "amount": "2422164173", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "781", + "owner": "kava1pen6a6z7qwfjjuamtacgwcvyflcyncqv06sfkt", + "principal": { + "amount": "344592046", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "790209", + "denom": "usdx" + }, + "collateral": { + "amount": "3174124192", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "783", + "owner": "kava17lx4arcck0settpt7ucfkjqg24qgx4jqwru68g", + "principal": { + "amount": "427285507", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "51312492", + "denom": "usdx" + }, + "collateral": { + "amount": "92114872630", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "784", + "owner": "kava1ghhk6fd4xtvxxu4v230x4acj27c2mkxe2tu7qm", + "principal": { + "amount": "12176872802", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2756", + "denom": "usdx" + }, + "collateral": { + "amount": "116823000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:28.231878135Z", + "id": "785", + "owner": "kava1c7wnzssvtrpa02nvxqxnjcctv3fngncy9apy4h", + "principal": { + "amount": "12463266", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1601246", + "denom": "usdx" + }, + "collateral": { + "amount": "4431366591", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "788", + "owner": "kava13vc2a42ea28d75tfuqmwykg7qxfrruzkdrwdug", + "principal": { + "amount": "442872624", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "4042", + "denom": "usdx" + }, + "collateral": { + "amount": "199997000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:00:08.102456799Z", + "id": "789", + "owner": "kava1jqmsfadczrmtpeu3g68yuvq846hrplm3uchru8", + "principal": { + "amount": "10463647", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "30364", + "denom": "usdx" + }, + "collateral": { + "amount": "89148279", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:36.711042819Z", + "id": "791", + "owner": "kava15sndhqjegzpc32xyw9le0vv0d6n8r0jyvhq9u4", + "principal": { + "amount": "12999672", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "27004", + "denom": "usdx" + }, + "collateral": { + "amount": "499923000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:50.915130002Z", + "id": "792", + "owner": "kava10pq9htfmwv35nsfke00tyfjsndqg5p09rzhtrf", + "principal": { + "amount": "55307782", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "40458", + "denom": "usdx" + }, + "collateral": { + "amount": "137934500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:05.765073985Z", + "id": "794", + "owner": "kava15m89rn38prgsffe8yyef7786ntnqskcz0sqc73", + "principal": { + "amount": "10189326", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "33241", + "denom": "usdx" + }, + "collateral": { + "amount": "97437142", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "799", + "owner": "kava1xq8ffuznqtu733gvazlfpgplkrj9wg3nyl79jr", + "principal": { + "amount": "10076116", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "167508", + "denom": "usdx" + }, + "collateral": { + "amount": "4316246000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "801", + "owner": "kava1vr30pdhcj4xp3kkft0gnhujrxvgrpgw9jvtdqj", + "principal": { + "amount": "490145215", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1993377", + "denom": "usdx" + }, + "collateral": { + "amount": "15051100578", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "804", + "owner": "kava14s6k9l2hqesptr0erwlpu70t36922wvm5qz8lt", + "principal": { + "amount": "1700000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "36962", + "denom": "usdx" + }, + "collateral": { + "amount": "226017050", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:36.711042819Z", + "id": "805", + "owner": "kava1ddgfxvftrdx372n3y8hqzmgafd4p4km8s9xalq", + "principal": { + "amount": "12133345", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "6669", + "denom": "usdx" + }, + "collateral": { + "amount": "98454000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:59:44.393525543Z", + "id": "806", + "owner": "kava1zuslhtgj5r8n95k833w5lttnjzuxcpjy7ql3c5", + "principal": { + "amount": "10004795", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "144340", + "denom": "usdx" + }, + "collateral": { + "amount": "499998000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:50.915130002Z", + "id": "812", + "owner": "kava103ykgmuyj782yznegdeph5yvj89w26aaw0mnt8", + "principal": { + "amount": "55000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "26045", + "denom": "usdx" + }, + "collateral": { + "amount": "460691000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "813", + "owner": "kava1vgxww69ecwvwl36d4k8a6errsfrm408t4gpzft", + "principal": { + "amount": "43377182", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3852", + "denom": "usdx" + }, + "collateral": { + "amount": "259700000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:11.309262057Z", + "id": "818", + "owner": "kava1tl2prafjdaxdq7y7rk9820r0xp0merzud4ttkn", + "principal": { + "amount": "10949014", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "19664447", + "denom": "usdx" + }, + "collateral": { + "amount": "51499861500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "823", + "owner": "kava1dwek8s78xay76gcflqd0jyn6fxmqt2yzzgfdh3", + "principal": { + "amount": "4251079477", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "9993204", + "denom": "usdx" + }, + "collateral": { + "amount": "26718603459", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "827", + "owner": "kava1au8ulcadj99qjr8vanzzyh5msgq3577xsxacsj", + "principal": { + "amount": "2224930979", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "45362", + "denom": "usdx" + }, + "collateral": { + "amount": "125000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:02:33.979597594Z", + "id": "829", + "owner": "kava18fz46zf48x74yhsrrqd6upvkw67yja2jts9q8j", + "principal": { + "amount": "13015724", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "343755", + "denom": "usdx" + }, + "collateral": { + "amount": "658020000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:27.75505786Z", + "id": "831", + "owner": "kava1jv2j4spatvrx65w7u75jxlp4p7duu7989nq22u", + "principal": { + "amount": "79709091", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "11171849", + "denom": "usdx" + }, + "collateral": { + "amount": "25860718548", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "834", + "owner": "kava10cgh5yf932zs5yaxhdf0rzzy2392f4uf5fs0a7", + "principal": { + "amount": "2591326246", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "422731", + "denom": "usdx" + }, + "collateral": { + "amount": "1199999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:43.897016316Z", + "id": "835", + "owner": "kava163r2fakg3xdvjy3vrq3a84f6fxxduetrj93lrk", + "principal": { + "amount": "136761825", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "73131", + "denom": "usdx" + }, + "collateral": { + "amount": "237746000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:31.545909484Z", + "id": "837", + "owner": "kava1a5s9spedfgcskr8cvf45w00m4exw066tjjg6sx", + "principal": { + "amount": "30679888", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "81495", + "denom": "usdx" + }, + "collateral": { + "amount": "204080858", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:05.765073985Z", + "id": "838", + "owner": "kava1yxhjnc3u2avecdqwj63n4xeymg958ausnjf8w7", + "principal": { + "amount": "18500000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "6476", + "denom": "usdx" + }, + "collateral": { + "amount": "900000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:45.943099302Z", + "id": "839", + "owner": "kava1ygratzmlvzz3nrzu4anfeq4yaturdv5eq7hfa2", + "principal": { + "amount": "11019549", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "165190", + "denom": "usdx" + }, + "collateral": { + "amount": "917984131", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:43.897016316Z", + "id": "842", + "owner": "kava1984kwcqxsr0gee5e7egtmlfah6lxt03xwz363f", + "principal": { + "amount": "104817394", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "34904", + "denom": "usdx" + }, + "collateral": { + "amount": "4613807813", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "845", + "owner": "kava13gjy32eew2x2snde9g7j64zz2vwmttupm6vs5t", + "principal": { + "amount": "650270742", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "352515", + "denom": "usdx" + }, + "collateral": { + "amount": "983761500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "846", + "owner": "kava1ze3euftmkdlt9e2smv0r3v3hn3v5xx7nnycm59", + "principal": { + "amount": "100041572", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "44369", + "denom": "usdx" + }, + "collateral": { + "amount": "220000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:20.647451252Z", + "id": "853", + "owner": "kava10gytfpmnffydm83at2hff3yuydnnzz2lghvely", + "principal": { + "amount": "10612364", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2474042", + "denom": "usdx" + }, + "collateral": { + "amount": "6216492198", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "854", + "owner": "kava1r8s9re6r6ak23u0ue6nsa7pfrthgfzergxf3gn", + "principal": { + "amount": "647091024", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "862770", + "denom": "usdx" + }, + "collateral": { + "amount": "2479823000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "855", + "owner": "kava1ltu99e6nyvvuzpcx580uj5r2nee4zfep0d2e9q", + "principal": { + "amount": "279017889", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "179422", + "denom": "usdx" + }, + "collateral": { + "amount": "491861500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:05.765073985Z", + "id": "859", + "owner": "kava19g7zfe7ncrxtmehsth0m6qklas9ywzxdqnenge", + "principal": { + "amount": "54937494", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "39705", + "denom": "usdx" + }, + "collateral": { + "amount": "125816092", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:05.765073985Z", + "id": "860", + "owner": "kava1e3c3wg748svce49arajje3quzk80ltqxknhggz", + "principal": { + "amount": "10701557", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "61217", + "denom": "usdx" + }, + "collateral": { + "amount": "170251594", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:03:52.213324724Z", + "id": "862", + "owner": "kava1rvjeepvt9snpa7m7x5kccmy3287vqj5rcmzamz", + "principal": { + "amount": "25759925", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "9387186", + "denom": "usdx" + }, + "collateral": { + "amount": "30104997000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "863", + "owner": "kava1hag49aychydfefvenqe38yedwly95sey0dae4m", + "principal": { + "amount": "3335162242", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "244109", + "denom": "usdx" + }, + "collateral": { + "amount": "1499980250", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:36.711042819Z", + "id": "865", + "owner": "kava1evgktxw4kwmx2skpqdg8rj0czxu922e4wptvt2", + "principal": { + "amount": "122782648", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3628", + "denom": "usdx" + }, + "collateral": { + "amount": "296360659", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:34.296774744Z", + "id": "866", + "owner": "kava1fu6w9xrfk0a9w3sgraln2mfvk3h6h05tfenr2w", + "principal": { + "amount": "10434423", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "4124", + "denom": "usdx" + }, + "collateral": { + "amount": "142350000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:00:01.347323184Z", + "id": "869", + "owner": "kava1z3rzlk084qnkrt0k0r73q2l7y88cvz52ywhejn", + "principal": { + "amount": "10927843", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1910", + "denom": "usdx" + }, + "collateral": { + "amount": "705993610", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:05.765073985Z", + "id": "870", + "owner": "kava1flsflys3g7sjs07tfrr0gvl56w6sqepw7zs4sd", + "principal": { + "amount": "10207260", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "771247", + "denom": "usdx" + }, + "collateral": { + "amount": "1999999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "871", + "owner": "kava1zpd87f3jjw5hmxc7rm0wd3k85x7e8qcntwn8gl", + "principal": { + "amount": "212301863", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "4532", + "denom": "usdx" + }, + "collateral": { + "amount": "98556000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:00:53.396708352Z", + "id": "878", + "owner": "kava149fsfmyz5790sv2r6xvf95mtytu9xm0nq6f8uv", + "principal": { + "amount": "10111419", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1693921", + "denom": "usdx" + }, + "collateral": { + "amount": "4958326340", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "881", + "owner": "kava1gz8hhxxl99y8cy0vray6dy8zwgkymyfvj2tgjn", + "principal": { + "amount": "548103005", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "10532", + "denom": "usdx" + }, + "collateral": { + "amount": "91305924", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:59:31.490669384Z", + "id": "882", + "owner": "kava132d7r249567tjtfs4n2le29jeeg40jp9yemtsk", + "principal": { + "amount": "10407232", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "37542", + "denom": "usdx" + }, + "collateral": { + "amount": "84318940", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "885", + "owner": "kava1gy8n6g26eqjf0k8nlxv0t88r34lnp7jgtg9s2p", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "623588741", + "denom": "usdx" + }, + "collateral": { + "amount": "1734167463466", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "886", + "owner": "kava1tstf3u4cw7u4xyu7wxdrnmrpvvmfamq3twcj7f", + "principal": { + "amount": "224998636481", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1976225", + "denom": "usdx" + }, + "collateral": { + "amount": "5187777610", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "890", + "owner": "kava1nx4ea0h0dhef880l920nw908dkkqdrwrlcc56y", + "principal": { + "amount": "620850940", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "13393", + "denom": "usdx" + }, + "collateral": { + "amount": "116271716", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:31.545909484Z", + "id": "891", + "owner": "kava10xdmc0zj4pg5lqxf885ljezzk6t30du5gqmgvx", + "principal": { + "amount": "10784526", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "40068", + "denom": "usdx" + }, + "collateral": { + "amount": "200168819", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "892", + "owner": "kava1my6zpnmut99u85rj50fvrnyfer6pf5kp8d74j3", + "principal": { + "amount": "28000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "239604", + "denom": "usdx" + }, + "collateral": { + "amount": "599999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:27.75505786Z", + "id": "894", + "owner": "kava1s454se9qfvaajfdh2c7vkt2u9fwvkfkvzy3a4w", + "principal": { + "amount": "70516246", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "175687", + "denom": "usdx" + }, + "collateral": { + "amount": "940385500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:14.400991279Z", + "id": "898", + "owner": "kava1lzjfwjzmlf376fnhj6gpvzy446664tvzn649hw", + "principal": { + "amount": "50859128", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "80247", + "denom": "usdx" + }, + "collateral": { + "amount": "249923000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:43.739056413Z", + "id": "899", + "owner": "kava1hg54sx9l9c6xc4m5sul5j9tgs3srnyxzvj8l4z", + "principal": { + "amount": "32997482", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "35732", + "denom": "usdx" + }, + "collateral": { + "amount": "349723000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "900", + "owner": "kava1x4phjjj9sg6tqgc660tl59fskk68ywsvm5hjv5", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "482663", + "denom": "usdx" + }, + "collateral": { + "amount": "1666305551", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "901", + "owner": "kava1v7veexlrmz2n5v4jw3ngdgu83fyazej7hwwjy7", + "principal": { + "amount": "195866401", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "270806", + "denom": "usdx" + }, + "collateral": { + "amount": "898545000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "902", + "owner": "kava16jrh3q9c0j96q3gettqrg7s2lpgvzr4f5u0gfp", + "principal": { + "amount": "100200794", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1276", + "denom": "usdx" + }, + "collateral": { + "amount": "199761500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:03:59.168880771Z", + "id": "903", + "owner": "kava13wtz6ae3j7t6n3fs5uwu5pyjkz93zh7n30nys9", + "principal": { + "amount": "14810328", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "21195", + "denom": "usdx" + }, + "collateral": { + "amount": "62000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:00:53.396708352Z", + "id": "904", + "owner": "kava1mrv7gwmwj4s9se2tvae0gv89pelax3tugfl7js", + "principal": { + "amount": "10102367", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "8390", + "denom": "usdx" + }, + "collateral": { + "amount": "19949995500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "905", + "owner": "kava16mue32jztkv7rzp50k6r23wx6nlnyyh0xr0u7t", + "principal": { + "amount": "2811117290", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "36715", + "denom": "usdx" + }, + "collateral": { + "amount": "99442669", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:27.75505786Z", + "id": "906", + "owner": "kava1cltnlz37arf9ywkkx6kj6u4qmjtm55h5yey0xr", + "principal": { + "amount": "10398903", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "70478", + "denom": "usdx" + }, + "collateral": { + "amount": "1030630957", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "909", + "owner": "kava1shqxy33cvadpzsm7lcyruwyjufcd6zqemjhtff", + "principal": { + "amount": "114497103", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "133412", + "denom": "usdx" + }, + "collateral": { + "amount": "710761500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:02.663985461Z", + "id": "911", + "owner": "kava1pt43yyefq2xu7zpuczqmt595wfmeh2ha2qu4r2", + "principal": { + "amount": "40000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "115974", + "denom": "usdx" + }, + "collateral": { + "amount": "683167180", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:36.711042819Z", + "id": "914", + "owner": "kava1e3fvhwlltc22g90vpcxjqghd7vf8u5wllsvf8h", + "principal": { + "amount": "85000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "34012", + "denom": "usdx" + }, + "collateral": { + "amount": "104360500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "915", + "owner": "kava163hks4cek5jg6p2ywk3f06vy6gh7pkltlmcjsl", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "33557", + "denom": "usdx" + }, + "collateral": { + "amount": "86144912", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "922", + "owner": "kava1gsmesaau9nwaz0tpaal758e9uvadlxwh4d4jyz", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "5756", + "denom": "usdx" + }, + "collateral": { + "amount": "210845917", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:31.545909484Z", + "id": "924", + "owner": "kava1l94lp2rg58cxkp8yz0yczezd5v5aem7v33dg95", + "principal": { + "amount": "21892685", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2393", + "denom": "usdx" + }, + "collateral": { + "amount": "91910854", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:57:13.731216849Z", + "id": "925", + "owner": "kava1jpcz2nje3ahnkejxyrhvzdnyftm5sfcg6mzt3f", + "principal": { + "amount": "10040964", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "26731", + "denom": "usdx" + }, + "collateral": { + "amount": "3422784750", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "927", + "owner": "kava1w22appkhcuy3ll4mpz67d35fl9wcv7ydf2k9zu", + "principal": { + "amount": "542056029", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "33942", + "denom": "usdx" + }, + "collateral": { + "amount": "100000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:58:31.264015933Z", + "id": "937", + "owner": "kava18fvar39w22u2juwwmd8ve93707gpx98qq99p9q", + "principal": { + "amount": "10167273", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1416057", + "denom": "usdx" + }, + "collateral": { + "amount": "5000373638", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "940", + "owner": "kava1l5xk08pn8cwwsd8gzgvgh5ef9n7e57fgm058rp", + "principal": { + "amount": "583405923", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "49515", + "denom": "usdx" + }, + "collateral": { + "amount": "497603973", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:00:22.713382299Z", + "id": "943", + "owner": "kava17rw3tlpwj4sr8xvhfpz5vv7a33zc7gzpnr57la", + "principal": { + "amount": "15000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "140636", + "denom": "usdx" + }, + "collateral": { + "amount": "1049999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "954", + "owner": "kava1z4flv307tmd77y7u66d5w27s90vcffjfzq9ee2", + "principal": { + "amount": "143369409", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "32797", + "denom": "usdx" + }, + "collateral": { + "amount": "499861500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "959", + "owner": "kava1tlgk8pxwcvkdxkgcc9fqfyu4qxg7thyzn0rhdr", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "640820", + "denom": "usdx" + }, + "collateral": { + "amount": "2549999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "960", + "owner": "kava1dqswms7d6javy8pv73r9v2sxgplurkkmfq5wpn", + "principal": { + "amount": "331916059", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "35550", + "denom": "usdx" + }, + "collateral": { + "amount": "100000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:00:31.529977202Z", + "id": "961", + "owner": "kava1suqkqpuxl5a9acajzfyr625jysevg8j67hwv2t", + "principal": { + "amount": "10963816", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "32028", + "denom": "usdx" + }, + "collateral": { + "amount": "100396886", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:59:44.393525543Z", + "id": "962", + "owner": "kava1dlyzmepcm60cj36jt2zet2jellkdm5uzjgj46r", + "principal": { + "amount": "10016890", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1019", + "denom": "usdx" + }, + "collateral": { + "amount": "100000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:02:09.942783911Z", + "id": "963", + "owner": "kava130rux6nveq6f7w7y34h736akupz0y73v3c6xv0", + "principal": { + "amount": "14339187", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "5499", + "denom": "usdx" + }, + "collateral": { + "amount": "99507500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "966", + "owner": "kava1ds3nf2q3ar8qprt0a0q2gw7ze7xy2hvqn8nyst", + "principal": { + "amount": "10000090", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "469150", + "denom": "usdx" + }, + "collateral": { + "amount": "1823584500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "968", + "owner": "kava1966kjxa5n9vg3te7khrx3zwg02pleemd04mffx", + "principal": { + "amount": "214745456", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "15706", + "denom": "usdx" + }, + "collateral": { + "amount": "99861500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:11.309262057Z", + "id": "970", + "owner": "kava1vjsnhq5h0jx6lnts3lf5rvc7nkenzngxjx4stl", + "principal": { + "amount": "10589651", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "505059", + "denom": "usdx" + }, + "collateral": { + "amount": "1799861500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "971", + "owner": "kava1vd4sh2z04wk8r3uq35defp8ermgwrqnvlw89s8", + "principal": { + "amount": "172394007", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "293958", + "denom": "usdx" + }, + "collateral": { + "amount": "1028897371", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "973", + "owner": "kava1pccn7ea8lvs5uqy7uv4d5s0n2l5chvfqhfqu45", + "principal": { + "amount": "99896581", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "505855", + "denom": "usdx" + }, + "collateral": { + "amount": "6444459575", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "974", + "owner": "kava13w0kf4f77cmjtgm5yvjqmqnjtyd92ukazdk0re", + "principal": { + "amount": "468804467", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3140", + "denom": "usdx" + }, + "collateral": { + "amount": "100000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:36.711042819Z", + "id": "976", + "owner": "kava16jpf48k46ta6j3efptnf7vup7kp7qq3jkmhu36", + "principal": { + "amount": "14007754", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "87989", + "denom": "usdx" + }, + "collateral": { + "amount": "600000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:50.815581672Z", + "id": "977", + "owner": "kava1ucce4lcy7mhnwqrkpys90ukc0nrt0700jg0t2u", + "principal": { + "amount": "65405705", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2930775", + "denom": "usdx" + }, + "collateral": { + "amount": "16009958500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "979", + "owner": "kava1wcanu7p4anpynf96vy6r5vcphcfdcah5zafrdj", + "principal": { + "amount": "1250000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "25803", + "denom": "usdx" + }, + "collateral": { + "amount": "66858594", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:59:44.393525543Z", + "id": "982", + "owner": "kava1yc5qftkw3rxcmucy027zx7rfyrsqhms32qfwej", + "principal": { + "amount": "10018310", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "660174", + "denom": "usdx" + }, + "collateral": { + "amount": "77231297342", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "984", + "owner": "kava1un2a96zhymexgdx9ujeldm2a6te9ar66n2en78", + "principal": { + "amount": "10263707651", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "16169", + "denom": "usdx" + }, + "collateral": { + "amount": "99823000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:58:31.264015933Z", + "id": "985", + "owner": "kava1c83e3fqpe2jjgcky22xjawery6spwq7365x430", + "principal": { + "amount": "10834226", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "353234", + "denom": "usdx" + }, + "collateral": { + "amount": "1431906978", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "988", + "owner": "kava1syee72y2ejrqvggynq0lhktkac88gzqffmz04c", + "principal": { + "amount": "158789577", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "5724", + "denom": "usdx" + }, + "collateral": { + "amount": "97364484", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "990", + "owner": "kava19j9hz6gr4tslnjr9ckqjxmd9rreag3kjmrz7nz", + "principal": { + "amount": "10071238", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "5181", + "denom": "usdx" + }, + "collateral": { + "amount": "60227274", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:02:09.942783911Z", + "id": "991", + "owner": "kava1zcmdwg43j0s6ukv23yur5f2qjkatmmapcwsfsq", + "principal": { + "amount": "10025334", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "165784", + "denom": "usdx" + }, + "collateral": { + "amount": "569656569", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:50.915130002Z", + "id": "992", + "owner": "kava1q40vl0wqju4upe7gafrzpuvcdev6gez5m747p6", + "principal": { + "amount": "64959797", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "15007", + "denom": "usdx" + }, + "collateral": { + "amount": "61538810", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:02:09.942783911Z", + "id": "997", + "owner": "kava18xvs8ergahd0s3fa40w7ce49mkytg4khtd58nw", + "principal": { + "amount": "10131228", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3765", + "denom": "usdx" + }, + "collateral": { + "amount": "69861500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:59:44.393525543Z", + "id": "999", + "owner": "kava10y72033n45jpu8nh26pws764ca62cspql6muln", + "principal": { + "amount": "10007967", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2360", + "denom": "usdx" + }, + "collateral": { + "amount": "99685103", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:55.262259649Z", + "id": "1001", + "owner": "kava1vlzmqht6g3ph0df03zf44r6h0rje5xkfsetlhr", + "principal": { + "amount": "10000914", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "57204", + "denom": "usdx" + }, + "collateral": { + "amount": "199999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:05.765073985Z", + "id": "1012", + "owner": "kava1lv0x52v8pxletxx75tfw3gjfq0yuhm6jwnefmt", + "principal": { + "amount": "19716265", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "127432", + "denom": "usdx" + }, + "collateral": { + "amount": "500000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:43.739056413Z", + "id": "1013", + "owner": "kava1q0eza4n6aa2k76zpjfjydeauvk0lgumxxy3f0v", + "principal": { + "amount": "45000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "82138", + "denom": "usdx" + }, + "collateral": { + "amount": "292910915", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:20.453076633Z", + "id": "1025", + "owner": "kava1t7uk5ds4ru2q56xnty6ryzxkkmaj8qju5r82zh", + "principal": { + "amount": "28865039", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "8130", + "denom": "usdx" + }, + "collateral": { + "amount": "111865103", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:00:31.529977202Z", + "id": "1026", + "owner": "kava1fgmpmaxpqmjjec3tjfjxjmxm9w89vnl5c9cwme", + "principal": { + "amount": "10958783", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "28567", + "denom": "usdx" + }, + "collateral": { + "amount": "89350000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "1028", + "owner": "kava1xfchqd6ymhw8lp6shzupkz66kj5smyu7lqjqqw", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "4840", + "denom": "usdx" + }, + "collateral": { + "amount": "152998000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:02:09.942783911Z", + "id": "1029", + "owner": "kava1y8xxdekejgews0rmtcm3c6qcwvhqcr48le90ju", + "principal": { + "amount": "10032472", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "7660557", + "denom": "usdx" + }, + "collateral": { + "amount": "38900000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1030", + "owner": "kava1kthd66zuvu03yk9ase9ju867pl9h493jfrua93", + "principal": { + "amount": "2800000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "16559", + "denom": "usdx" + }, + "collateral": { + "amount": "298942469", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "1034", + "owner": "kava1m974xquf5w7j043uspalpulxkm0nf48st65mys", + "principal": { + "amount": "10002320", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "9881", + "denom": "usdx" + }, + "collateral": { + "amount": "98152192", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:00:22.713382299Z", + "id": "1035", + "owner": "kava1gmdmcrppy9pv8fyu5apa6majvf3p89nhsczhgz", + "principal": { + "amount": "10244433", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "28002", + "denom": "usdx" + }, + "collateral": { + "amount": "181351271", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "1038", + "owner": "kava18hv6fqwe83jrg7vmark9mspewv6p6u3k5nqskn", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2058", + "denom": "usdx" + }, + "collateral": { + "amount": "98572000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:09.136574316Z", + "id": "1040", + "owner": "kava15xc7hkst2huv0sgr4eqw6dr50emwsw894xgwqf", + "principal": { + "amount": "10016297", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "494048", + "denom": "usdx" + }, + "collateral": { + "amount": "2499861500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "1045", + "owner": "kava125y60srn5rp8ay4j2url380jyvrnjvy6qse609", + "principal": { + "amount": "200000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "100262", + "denom": "usdx" + }, + "collateral": { + "amount": "510961500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:43.739056413Z", + "id": "1051", + "owner": "kava1a4ssa9ntvjrva0xvndvapza5saw6d8t66gnzph", + "principal": { + "amount": "45000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "4330", + "denom": "usdx" + }, + "collateral": { + "amount": "99861500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:03:28.737551656Z", + "id": "1054", + "owner": "kava15yns68g0sc5en5h3qdpfs7ydd93n94r0gyuh8d", + "principal": { + "amount": "10998888", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "33061", + "denom": "usdx" + }, + "collateral": { + "amount": "115313787", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:48.64965597Z", + "id": "1055", + "owner": "kava13833lua3wuczhdrg2m6antnryyfqzxnjxhxpej", + "principal": { + "amount": "12351720", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "578", + "denom": "usdx" + }, + "collateral": { + "amount": "96328000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:02.663985461Z", + "id": "1056", + "owner": "kava15ex4ng3943n0eclcjc5zz22rmqy04mgp4wqx6r", + "principal": { + "amount": "10162349", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "28815", + "denom": "usdx" + }, + "collateral": { + "amount": "100000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:58:31.264015933Z", + "id": "1057", + "owner": "kava1ztgycvjv9vqjtvn9qp54l7mcczmvr22y4zvspe", + "principal": { + "amount": "10844849", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "244234", + "denom": "usdx" + }, + "collateral": { + "amount": "1009998000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1058", + "owner": "kava1wdyd2lpllxk2t9mg3qe5gqlgzvvf08ns380u3g", + "principal": { + "amount": "100000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "59199", + "denom": "usdx" + }, + "collateral": { + "amount": "500582500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "1060", + "owner": "kava1gp7k90kaatayu9cgnzmp02a0dmgfyye67zyup8", + "principal": { + "amount": "63487004", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "966269", + "denom": "usdx" + }, + "collateral": { + "amount": "4773509000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1062", + "owner": "kava14pq4u6w5p5qawu8mxhsvahrlfzxq3g544agczl", + "principal": { + "amount": "404099235", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "249248", + "denom": "usdx" + }, + "collateral": { + "amount": "6134992000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1063", + "owner": "kava1tzzdns8zkl0qptywnpr27eh0evj9zu45pc8f0g", + "principal": { + "amount": "744627796", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "161107", + "denom": "usdx" + }, + "collateral": { + "amount": "856218750", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:36.711042819Z", + "id": "1064", + "owner": "kava1lvwpkfterjc48mmuja4gps0u4k8mwmx5hpyzgm", + "principal": { + "amount": "84569577", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "83377", + "denom": "usdx" + }, + "collateral": { + "amount": "1009684500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1066", + "owner": "kava10x9egqv6wyd9mjvtmd4h97hpa7ha259a2t0zux", + "principal": { + "amount": "140215720", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "25372", + "denom": "usdx" + }, + "collateral": { + "amount": "90930528", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "1067", + "owner": "kava1d0qym0r8harr3jhphzeasst8jchhfcx58egdqw", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "26218", + "denom": "usdx" + }, + "collateral": { + "amount": "102733805", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:02:59.644377189Z", + "id": "1068", + "owner": "kava14dnwu4xmzur37zatgfd3mg8cjphs0k2lkyxyyy", + "principal": { + "amount": "12342513", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "257461", + "denom": "usdx" + }, + "collateral": { + "amount": "1374108876", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:36.711042819Z", + "id": "1069", + "owner": "kava10zj8d0kwdfz5v7yhdpkxpwcmgr44yhg6da58dm", + "principal": { + "amount": "109950726", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "554185", + "denom": "usdx" + }, + "collateral": { + "amount": "2799861500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "1071", + "owner": "kava1nh9l69guvs8apf74mqgp7yyfgddd3pnx9tfdpw", + "principal": { + "amount": "243333418", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "43407", + "denom": "usdx" + }, + "collateral": { + "amount": "175081938", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:05.765073985Z", + "id": "1072", + "owner": "kava1f9gr72w4f5x8e6n4naaqh9ep64qsut87227yy3", + "principal": { + "amount": "18443056", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "82194", + "denom": "usdx" + }, + "collateral": { + "amount": "354856061", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "1073", + "owner": "kava1e9zw63uwaz3jhejq2f2pv9dkg3y2vafq4v2d60", + "principal": { + "amount": "40438266", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "884754", + "denom": "usdx" + }, + "collateral": { + "amount": "4656753500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1075", + "owner": "kava1a6gehaye2j5gnv0v2670n8mg40sc5z44nxj8lh", + "principal": { + "amount": "402512839", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2638", + "denom": "usdx" + }, + "collateral": { + "amount": "99281838", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "1077", + "owner": "kava17uvhem6mefz6qqacu6w455d6af48qtqg4zcrrg", + "principal": { + "amount": "10201555", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "24397", + "denom": "usdx" + }, + "collateral": { + "amount": "199722000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:50.815581672Z", + "id": "1078", + "owner": "kava1dlhhf0jewx7m0j5nsm8gkke32ytggxk0dx436z", + "principal": { + "amount": "15000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "179936", + "denom": "usdx" + }, + "collateral": { + "amount": "881354038", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1079", + "owner": "kava17lc8kscue95emdyaswhhh8narnxct7klrgp544", + "principal": { + "amount": "119873381", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "97497", + "denom": "usdx" + }, + "collateral": { + "amount": "500000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1080", + "owner": "kava17h0a2xr7c6e0e2eyp2jhpg6udkgrg6vrdf85wr", + "principal": { + "amount": "71630853", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1178760", + "denom": "usdx" + }, + "collateral": { + "amount": "25479494037", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1081", + "owner": "kava1kyq6kgxvsfd4w4km43hcqv6jejnmu78q8cj0l7", + "principal": { + "amount": "3511445626", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "4731860", + "denom": "usdx" + }, + "collateral": { + "amount": "20599723000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1082", + "owner": "kava1frqzm6zcjnn8fwq46tfchn64vyvp4lma7440sw", + "principal": { + "amount": "2772221139", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "15705", + "denom": "usdx" + }, + "collateral": { + "amount": "117363612", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:00:31.529977202Z", + "id": "1084", + "owner": "kava1madvye95n3pps3g42s2g33e8nz6yg0m4eqad23", + "principal": { + "amount": "10962916", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "7322", + "denom": "usdx" + }, + "collateral": { + "amount": "98306194", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:58:40.320250584Z", + "id": "1086", + "owner": "kava18v3u8ehl46kkujm6mzp2faqwdhk6dc3j48jzv5", + "principal": { + "amount": "10145787", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "4547", + "denom": "usdx" + }, + "collateral": { + "amount": "105146500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:05.765073985Z", + "id": "1087", + "owner": "kava1tgs73yuhrg32cnlc09r7r7v9r5l96j2tegmxmj", + "principal": { + "amount": "15190284", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "23162", + "denom": "usdx" + }, + "collateral": { + "amount": "80000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "1089", + "owner": "kava1h8kqkqlgcnl09djvxfz7j68ct8q79x5vf4zdjt", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "81338", + "denom": "usdx" + }, + "collateral": { + "amount": "410000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:36.983876875Z", + "id": "1092", + "owner": "kava1xevtu9l5n5ztx65xnlyp6wwkl28curelc8wpkx", + "principal": { + "amount": "41045467", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "18356", + "denom": "usdx" + }, + "collateral": { + "amount": "59805500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:34.296774744Z", + "id": "1095", + "owner": "kava1a0kkecrgvuvume6el50u7pvxnqn8xrpkn9j64z", + "principal": { + "amount": "10149888", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1820931", + "denom": "usdx" + }, + "collateral": { + "amount": "8399999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1097", + "owner": "kava1gf2a33yz07peuk0xzhg7w0nrhs03858ewnck5k", + "principal": { + "amount": "1082520810", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "5116", + "denom": "usdx" + }, + "collateral": { + "amount": "541492075", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:27.75505786Z", + "id": "1100", + "owner": "kava13cc9ysrtqw4uzalgfyzt2ezlj4sdu8tfdrw57v", + "principal": { + "amount": "79171774", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "45979", + "denom": "usdx" + }, + "collateral": { + "amount": "999999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1101", + "owner": "kava1ju72ykesecrggfk35uawdtgjxdxqcpjla5n6c0", + "principal": { + "amount": "100083216", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "26642", + "denom": "usdx" + }, + "collateral": { + "amount": "1634909684", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "1103", + "owner": "kava1lgfa45c9ukzxmtfhdmx0k4dnt4whph28csdds3", + "principal": { + "amount": "164499793", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "5367", + "denom": "usdx" + }, + "collateral": { + "amount": "183861500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:45.943099302Z", + "id": "1107", + "owner": "kava1su2zgzekk4xqn53z68jqnz4w6djl2vf76qh2de", + "principal": { + "amount": "26960780", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "10863", + "denom": "usdx" + }, + "collateral": { + "amount": "2399995000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "1108", + "owner": "kava1vkhtmn2awzg2wsu9uujw455kcce2msxc078325", + "principal": { + "amount": "186351626", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "5522", + "denom": "usdx" + }, + "collateral": { + "amount": "667867478", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:27.75505786Z", + "id": "1109", + "owner": "kava14y0c4e883xwr3mp0wexvnp6knsd4me62ampna8", + "principal": { + "amount": "86521146", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "171662", + "denom": "usdx" + }, + "collateral": { + "amount": "1199999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:27.75505786Z", + "id": "1110", + "owner": "kava16fkalpvmzvs2jnr2nemwnna53d60pf4mrjvtfd", + "principal": { + "amount": "111061760", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "99522", + "denom": "usdx" + }, + "collateral": { + "amount": "346257612", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:14.400991279Z", + "id": "1111", + "owner": "kava1fzptzt0cr88ne6ly4kts0pwnm7c4kxkuu5zxas", + "principal": { + "amount": "50962194", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "36326", + "denom": "usdx" + }, + "collateral": { + "amount": "196861500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:50.915130002Z", + "id": "1112", + "owner": "kava1lz0dv3tanz398yt4tfgnddah0desphmekk67cg", + "principal": { + "amount": "18061148", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "54953", + "denom": "usdx" + }, + "collateral": { + "amount": "314898833", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:43.739056413Z", + "id": "1114", + "owner": "kava1p8azx3q0r3r7j9u8rrlcjmgadsuz0vnvufweg3", + "principal": { + "amount": "33050883", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "302294", + "denom": "usdx" + }, + "collateral": { + "amount": "1589661500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "1115", + "owner": "kava1dmfc20gm0f4lnu0fuuq7c24tyjrdurfkfp49dm", + "principal": { + "amount": "176734207", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "29723", + "denom": "usdx" + }, + "collateral": { + "amount": "93525560", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:00:22.713382299Z", + "id": "1116", + "owner": "kava1w0grk3qszlmcas2dwqvq5ayehgpwqfrhj3gxsn", + "principal": { + "amount": "15000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "185314", + "denom": "usdx" + }, + "collateral": { + "amount": "1069338027", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1120", + "owner": "kava1n8y0wh5aau0ke9q9jp9zapjnxxd87mwdvhr0p5", + "principal": { + "amount": "103006416", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "723", + "denom": "usdx" + }, + "collateral": { + "amount": "96046900", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "1121", + "owner": "kava1skjcua56k0cmvndwscadl7u46v52veyyynglra", + "principal": { + "amount": "10003443", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "139285", + "denom": "usdx" + }, + "collateral": { + "amount": "799584500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:36.711042819Z", + "id": "1122", + "owner": "kava16h66fzp2p63ayhvuacss6r4tvhsjs0qf6u472h", + "principal": { + "amount": "83867665", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3555", + "denom": "usdx" + }, + "collateral": { + "amount": "94213574", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:00:08.102456799Z", + "id": "1123", + "owner": "kava1s3pem3p4vtgszlas2qv9hkxa43xms9fhdk23x3", + "principal": { + "amount": "10467073", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "14400", + "denom": "usdx" + }, + "collateral": { + "amount": "410161543", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:50.915130002Z", + "id": "1124", + "owner": "kava1ugg73fn4x5urnxyzzxc60qksnpjwjdnhh03sjp", + "principal": { + "amount": "42523870", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "755204", + "denom": "usdx" + }, + "collateral": { + "amount": "4999961500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1125", + "owner": "kava1mkh4v9zpxc3g0zkjf8c2vt2pue2xce2yxkr8s0", + "principal": { + "amount": "450000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "112587", + "denom": "usdx" + }, + "collateral": { + "amount": "1060204111", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1127", + "owner": "kava1zend29hj3dh3e6ksvp05dls700jehajw2qgp2z", + "principal": { + "amount": "142014972", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "73400", + "denom": "usdx" + }, + "collateral": { + "amount": "847923000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1128", + "owner": "kava1krfy0mvum7gve4k3zwakny4ywyw9444v2clryc", + "principal": { + "amount": "56000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "10978", + "denom": "usdx" + }, + "collateral": { + "amount": "99999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:02:09.942783911Z", + "id": "1129", + "owner": "kava1tkk7z4w7kc8c3uf85ypjq2ch5x2h7ardrwykrv", + "principal": { + "amount": "10032163", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "9976", + "denom": "usdx" + }, + "collateral": { + "amount": "79191665", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:59:44.393525543Z", + "id": "1130", + "owner": "kava1rau6y74vp3exf0we0skz8h2ps3srtvymz0c2m0", + "principal": { + "amount": "10013418", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "108678", + "denom": "usdx" + }, + "collateral": { + "amount": "647420107", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:36.711042819Z", + "id": "1131", + "owner": "kava19e7mx9ajlmztzaysx0xp65y3xwud7juamajmwx", + "principal": { + "amount": "60000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "388156", + "denom": "usdx" + }, + "collateral": { + "amount": "2749724000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "1132", + "owner": "kava1qql0h04u6n244uu4gzpl8fegpzfk30t8qfmeyd", + "principal": { + "amount": "220000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "330123", + "denom": "usdx" + }, + "collateral": { + "amount": "2079961500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "1133", + "owner": "kava1m32nfspk6l4ywdrv2mxwyz75s2tujcrct2sxys", + "principal": { + "amount": "190500000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "5071", + "denom": "usdx" + }, + "collateral": { + "amount": "84103000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:00:53.396708352Z", + "id": "1136", + "owner": "kava14ewkuy3szkkdhdsgy4k87xcg67tvujnsm7arr9", + "principal": { + "amount": "10104049", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2491", + "denom": "usdx" + }, + "collateral": { + "amount": "99961500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:59:44.393525543Z", + "id": "1137", + "owner": "kava1d7h24gvk2hzq5ysycz7ras8ylzmraym4xar204", + "principal": { + "amount": "10013242", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1341", + "denom": "usdx" + }, + "collateral": { + "amount": "149999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:55.262259649Z", + "id": "1138", + "owner": "kava1a4th2q9fvv6q5ssfrx8flly09dcn9g3s4lqy4h", + "principal": { + "amount": "10059749", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "18780", + "denom": "usdx" + }, + "collateral": { + "amount": "121770000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "1139", + "owner": "kava15u9yth0fyg8e9cde7smsxdezj2w07afnc2ygwk", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "8077", + "denom": "usdx" + }, + "collateral": { + "amount": "220793241", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "1140", + "owner": "kava1sf9fkql92spg0nqyjqlyrvv9ty2e7dqt6a374m", + "principal": { + "amount": "10000054", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2316", + "denom": "usdx" + }, + "collateral": { + "amount": "99310452", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:02:09.942783911Z", + "id": "1142", + "owner": "kava1688jl7fanlpnrc22wen368g8879662eu0yfk7j", + "principal": { + "amount": "10021641", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "11244", + "denom": "usdx" + }, + "collateral": { + "amount": "1244050055", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "1144", + "owner": "kava12qq5jfczwdtz3682nretdw29fwceeeug3cv767", + "principal": { + "amount": "190279909", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "27908", + "denom": "usdx" + }, + "collateral": { + "amount": "199999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:00:22.713382299Z", + "id": "1145", + "owner": "kava1jr58355f3waf98sujfshuzf2qk7s63tqh90fy5", + "principal": { + "amount": "15000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "158922", + "denom": "usdx" + }, + "collateral": { + "amount": "864235131", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1146", + "owner": "kava187vqgkz0p4279ckuf4lnuk3zrxz3w92r3jzflh", + "principal": { + "amount": "102150509", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "90105", + "denom": "usdx" + }, + "collateral": { + "amount": "609861500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "1149", + "owner": "kava1qjsh569wv0frufrzescdu38rxmdvxfwsqee253", + "principal": { + "amount": "50000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "301566", + "denom": "usdx" + }, + "collateral": { + "amount": "3201052123", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "1150", + "owner": "kava19w04elv89rwygj4t6qf4cwq5fpdgcfn03k740f", + "principal": { + "amount": "220000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "63217", + "denom": "usdx" + }, + "collateral": { + "amount": "349571500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:55.262259649Z", + "id": "1151", + "owner": "kava13ahfrdmr383r5skkxqecn3zjk93kjdjtvat22a", + "principal": { + "amount": "35000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "52208", + "denom": "usdx" + }, + "collateral": { + "amount": "401204683", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:36.711042819Z", + "id": "1154", + "owner": "kava1nxg24gzzh9k8pl06frvp7989g3kk4ualgqkylx", + "principal": { + "amount": "59991261", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "85181", + "denom": "usdx" + }, + "collateral": { + "amount": "2197108459", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "1155", + "owner": "kava16l9y9utg6j8u0vk3mcrdu7xampr4z24xuxr58g", + "principal": { + "amount": "338436534", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "87183", + "denom": "usdx" + }, + "collateral": { + "amount": "499999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "1156", + "owner": "kava1ce4c7qc9zyfp45emhvjjy8470xwastdca2qxjg", + "principal": { + "amount": "50000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "753789", + "denom": "usdx" + }, + "collateral": { + "amount": "4899999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1157", + "owner": "kava1qyuxcegvmxphwsm34gf0l3l9ldxn0zfmj9pazu", + "principal": { + "amount": "481711308", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "91716", + "denom": "usdx" + }, + "collateral": { + "amount": "699998000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:27.75505786Z", + "id": "1160", + "owner": "kava1yrzmk4y24da8kn9c84w7pxkpjfntmszmh5rr9l", + "principal": { + "amount": "70391899", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "239975", + "denom": "usdx" + }, + "collateral": { + "amount": "37200000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1163", + "owner": "kava1xzqca09l2nkrjqtrqwqe4l3fj5hzc685c6dl2h", + "principal": { + "amount": "5959354317", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "30969", + "denom": "usdx" + }, + "collateral": { + "amount": "181723000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:03:52.213324724Z", + "id": "1164", + "owner": "kava145cfm44fzv87gg3yudqkqj8ejmff5252agwpsu", + "principal": { + "amount": "17676692", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "57856", + "denom": "usdx" + }, + "collateral": { + "amount": "267399000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1165", + "owner": "kava1k738mvz97wp93h97jj5f7jvxurkypay3tr0xmc", + "principal": { + "amount": "33917492", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "39294", + "denom": "usdx" + }, + "collateral": { + "amount": "199961500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:11.309262057Z", + "id": "1168", + "owner": "kava1z6j0d4352ljna6rjgcr8d5cl4mt3tsng0z9dux", + "principal": { + "amount": "29166067", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "29723", + "denom": "usdx" + }, + "collateral": { + "amount": "6400814130", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1169", + "owner": "kava10zl70qnnf0wgxx6eu9mn6k0tmrn0yqevsxv806", + "principal": { + "amount": "650744461", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "462345", + "denom": "usdx" + }, + "collateral": { + "amount": "15299723000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1170", + "owner": "kava1q74kea59tmpelupa7mkq6cj697l07cjmnf4l5j", + "principal": { + "amount": "1600337837", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "18077", + "denom": "usdx" + }, + "collateral": { + "amount": "129884500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:50.915130002Z", + "id": "1172", + "owner": "kava1hmgz6wjr6gwehda53zy7r74tteyx7pvqtw9d59", + "principal": { + "amount": "10800000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3055", + "denom": "usdx" + }, + "collateral": { + "amount": "187224202", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "1173", + "owner": "kava1vrdmnppmyfas5vuqj8wdm847gatvf9ehg4k5ej", + "principal": { + "amount": "10000117", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "14762", + "denom": "usdx" + }, + "collateral": { + "amount": "604137456", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:59:44.393525543Z", + "id": "1174", + "owner": "kava1zfsfrdyhyuyw462r3e358aj43r2nsp9vexp2vc", + "principal": { + "amount": "10009895", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "16166", + "denom": "usdx" + }, + "collateral": { + "amount": "101521504", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "1176", + "owner": "kava12l48p8ldfkgxwpdyhqavy2psfzapc8jx5g649k", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1300", + "denom": "usdx" + }, + "collateral": { + "amount": "99167445", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:58:21.656230122Z", + "id": "1177", + "owner": "kava1w0z0u03vcl3pt9yfxls2anfxr7s23d70dhkgvz", + "principal": { + "amount": "10147761", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "71449", + "denom": "usdx" + }, + "collateral": { + "amount": "441821492", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:14.400991279Z", + "id": "1178", + "owner": "kava1288mlnjrrp0zckg36f08v47a2qfq6v3tlmppnz", + "principal": { + "amount": "45836972", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "23618", + "denom": "usdx" + }, + "collateral": { + "amount": "141671045", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:00:22.713382299Z", + "id": "1180", + "owner": "kava1tu2zvgn3q6ukz9kc0j65z2dgzd25re3gwnjp2n", + "principal": { + "amount": "15000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "74339", + "denom": "usdx" + }, + "collateral": { + "amount": "419417553", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "1181", + "owner": "kava13yml6zhu6xspua5kn8rrwxwr8mpqwcn8u7znsl", + "principal": { + "amount": "50000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3564", + "denom": "usdx" + }, + "collateral": { + "amount": "75109023", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:43.739056413Z", + "id": "1182", + "owner": "kava1ncaqhfhug3lxkj99vv0wqjkm29388vtdy0h3e4", + "principal": { + "amount": "10022157", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "157027", + "denom": "usdx" + }, + "collateral": { + "amount": "6038886034", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1183", + "owner": "kava18jmkxet5tr0eyrklk2zctcjegu6zdkudmgkqpn", + "principal": { + "amount": "721477508", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "4119081", + "denom": "usdx" + }, + "collateral": { + "amount": "27094688909", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1184", + "owner": "kava1f9qfd6vxluuv7tj0wdnwgv5paskq208jhzan0s", + "principal": { + "amount": "3041123051", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "22717", + "denom": "usdx" + }, + "collateral": { + "amount": "146953276", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "1186", + "owner": "kava1yc7aedn8a3k99yvknp877gg5spwtgverz9wcww", + "principal": { + "amount": "15245734", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "21175", + "denom": "usdx" + }, + "collateral": { + "amount": "135648304", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:07.335098476Z", + "id": "1187", + "owner": "kava1ljcfr9vcl7pe8k0vcrsf5tad80mmac2twq6t2e", + "principal": { + "amount": "14245538", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "11465", + "denom": "usdx" + }, + "collateral": { + "amount": "105300039", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:00:22.713382299Z", + "id": "1188", + "owner": "kava1yu5d5wugkr3ed2rmxkyd3kq36jx7hdg8phmfz3", + "principal": { + "amount": "10653851", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1956", + "denom": "usdx" + }, + "collateral": { + "amount": "62196553", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:55.262259649Z", + "id": "1190", + "owner": "kava1d9kgaeuj2k66585pc5rnc0fmyk4hd462v8hera", + "principal": { + "amount": "10001927", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "7240", + "denom": "usdx" + }, + "collateral": { + "amount": "194292500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:59:00.929004542Z", + "id": "1191", + "owner": "kava14pafwfsn42jtlk6syjfvuzde5klr9q8srf2uxl", + "principal": { + "amount": "11384136", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "137399", + "denom": "usdx" + }, + "collateral": { + "amount": "1153083837", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "1192", + "owner": "kava1gk4qrjfylpvkrl8phpnxkdrm0yf5w3l4hw9uzh", + "principal": { + "amount": "134030202", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "61428", + "denom": "usdx" + }, + "collateral": { + "amount": "429020826", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "1195", + "owner": "kava10lffqz334n4feznc9ys9z0tpcu57qlw2n78afr", + "principal": { + "amount": "45382603", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "512056", + "denom": "usdx" + }, + "collateral": { + "amount": "3999961500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1196", + "owner": "kava1gdgx34jhu0hjvaq5wuzwaapa8cg8mc2jmc4v4w", + "principal": { + "amount": "435941403", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "65704", + "denom": "usdx" + }, + "collateral": { + "amount": "400000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:36.711042819Z", + "id": "1198", + "owner": "kava1cqwh57xurahm5dyq4ye2f7aelcsqh7m6kqp08x", + "principal": { + "amount": "60000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "63167", + "denom": "usdx" + }, + "collateral": { + "amount": "500761500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:27.75505786Z", + "id": "1199", + "owner": "kava1f267je8z7j8hhx8zhe457ucrgzc98sjrh2jjpx", + "principal": { + "amount": "49566284", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "13176", + "denom": "usdx" + }, + "collateral": { + "amount": "156162066", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:05.765073985Z", + "id": "1200", + "owner": "kava1rdy5aphvh5pw2tuv0u3l5mfqx5zwutatcyjf48", + "principal": { + "amount": "21000983", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "177597", + "denom": "usdx" + }, + "collateral": { + "amount": "4306960500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1201", + "owner": "kava1r7uckqzflqdqcwllh3ty36qvzl0z7utv5ujh3l", + "principal": { + "amount": "415450586", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "121729", + "denom": "usdx" + }, + "collateral": { + "amount": "1189610500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1202", + "owner": "kava1c5lzj543l3xlz8s4s03phkkm4p0g6qg570vjys", + "principal": { + "amount": "103205069", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "153270", + "denom": "usdx" + }, + "collateral": { + "amount": "1570133310", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1203", + "owner": "kava10p3y2uvu36ywvtaf98m07c8wgm0ud4cre8z4ty", + "principal": { + "amount": "130000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "54387", + "denom": "usdx" + }, + "collateral": { + "amount": "599861500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "1206", + "owner": "kava1gvnvk9v46eaecfnq46x9e4wtq9snku77ne7c0f", + "principal": { + "amount": "50138842", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "5285", + "denom": "usdx" + }, + "collateral": { + "amount": "499961500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:36.711042819Z", + "id": "1208", + "owner": "kava18ptdegs5fezrq8eyqemwyhfhpjwwsch66ve9yd", + "principal": { + "amount": "80047442", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "12073", + "denom": "usdx" + }, + "collateral": { + "amount": "100301500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:59:31.490669384Z", + "id": "1210", + "owner": "kava1my9zsmtzxceytqfhtun6mahtpx4yr5cq4s5uqr", + "principal": { + "amount": "11200079", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "5862", + "denom": "usdx" + }, + "collateral": { + "amount": "95817622", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:20.647451252Z", + "id": "1211", + "owner": "kava19javdflgtlzpshn2r5xqlzwfy3h3dada7344xh", + "principal": { + "amount": "10610281", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "17582", + "denom": "usdx" + }, + "collateral": { + "amount": "116463505", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:48.64965597Z", + "id": "1212", + "owner": "kava1qct3ma2vxr22hmnm50p538540ngf65jnmffvgy", + "principal": { + "amount": "17350000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "21758", + "denom": "usdx" + }, + "collateral": { + "amount": "255486630", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:20.453076633Z", + "id": "1213", + "owner": "kava160e4kdajay7784je5gvfeey8ufpglmr6gy0564", + "principal": { + "amount": "26887326", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "111955", + "denom": "usdx" + }, + "collateral": { + "amount": "1000026811", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:43.897016316Z", + "id": "1215", + "owner": "kava140xym4ugfwtqy6kdrrhvptrm0teah9t6vt5kup", + "principal": { + "amount": "135000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "47030", + "denom": "usdx" + }, + "collateral": { + "amount": "1399961500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1216", + "owner": "kava14yh6p6n0kl5v6qr6z448sqzmn9lplkwqn0c8jz", + "principal": { + "amount": "100044728", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "17802", + "denom": "usdx" + }, + "collateral": { + "amount": "258921500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:02:49.66052784Z", + "id": "1219", + "owner": "kava166fuedyd35g57vuuvwyr9pfdl47xqn7ag0unga", + "principal": { + "amount": "23000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3686", + "denom": "usdx" + }, + "collateral": { + "amount": "99961500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:57:13.731216849Z", + "id": "1221", + "owner": "kava1gfca993p3ety784mhed7cqfgjln9n622u4p49x", + "principal": { + "amount": "10040204", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "60405", + "denom": "usdx" + }, + "collateral": { + "amount": "1251061946", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1222", + "owner": "kava1er6s83mm2madft79f37ewe2ljlya30awgcrp9d", + "principal": { + "amount": "117901153", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "7624", + "denom": "usdx" + }, + "collateral": { + "amount": "599923000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "1225", + "owner": "kava12z9k00k7dje9vnpfkkqsr0e7fy795dqjjugqn8", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "44171", + "denom": "usdx" + }, + "collateral": { + "amount": "699923000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:36.711042819Z", + "id": "1227", + "owner": "kava1qutky6rkm8002vsd5mf39wfujr9lpgehevf3ny", + "principal": { + "amount": "60000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "133253", + "denom": "usdx" + }, + "collateral": { + "amount": "1842478500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "1228", + "owner": "kava1u2vfd56wfs3d7gq25dn5x5z2zhmwzsmdadut45", + "principal": { + "amount": "219271531", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "4873669", + "denom": "usdx" + }, + "collateral": { + "amount": "499980824210", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1229", + "owner": "kava1as5f599ltjc9uy5dpne9pkhzuylcdhsj7sa2du", + "principal": { + "amount": "83211287797", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "4864", + "denom": "usdx" + }, + "collateral": { + "amount": "509998000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:27.75505786Z", + "id": "1231", + "owner": "kava1p42hz5v9330x7hrx07xgl5g7tw55vgkm2mdk9p", + "principal": { + "amount": "87037238", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "52260", + "denom": "usdx" + }, + "collateral": { + "amount": "6509723000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1232", + "owner": "kava1gpqjt96w5kef6u7almss4h378tdjar0grnngd8", + "principal": { + "amount": "930508189", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "454", + "denom": "usdx" + }, + "collateral": { + "amount": "100000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:58:31.264015933Z", + "id": "1238", + "owner": "kava13d3nklvf22whykz5a8vt8qlj66029gpwqcmj69", + "principal": { + "amount": "10002138", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "314932", + "denom": "usdx" + }, + "collateral": { + "amount": "44070000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1239", + "owner": "kava1de5gcyqfjldkmsmafa23zversglczynan76h6p", + "principal": { + "amount": "6152574597", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "47534", + "denom": "usdx" + }, + "collateral": { + "amount": "5624859500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1244", + "owner": "kava1r7slfdygrmkyhd52q7gdq2c2n6aysk97w3xkve", + "principal": { + "amount": "900271101", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "4638", + "denom": "usdx" + }, + "collateral": { + "amount": "104711500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:00:08.102456799Z", + "id": "1246", + "owner": "kava1scykt2dj20ysamp2ysrtuymxnt4xlthj0tk3v6", + "principal": { + "amount": "10461790", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "7185", + "denom": "usdx" + }, + "collateral": { + "amount": "79961500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "1247", + "owner": "kava1pphezceeqfag2x64g4sgmun8k2y0a2tvd6z2v6", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "133668", + "denom": "usdx" + }, + "collateral": { + "amount": "210000000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1251", + "owner": "kava15whxe2p0exnpw5wze2f3kllwhhqlq23054knmc", + "principal": { + "amount": "37023643188", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "6919", + "denom": "usdx" + }, + "collateral": { + "amount": "99999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:00:53.396708352Z", + "id": "1252", + "owner": "kava19fl64dfhnmzs6vkc3al60swdps7qlkfd57sk3t", + "principal": { + "amount": "10111683", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "5202", + "denom": "usdx" + }, + "collateral": { + "amount": "177314529", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "1254", + "owner": "kava1696468hu2u839dh8zarjyqw6k835yrttvr3ngx", + "principal": { + "amount": "10000120", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "6515", + "denom": "usdx" + }, + "collateral": { + "amount": "67342419", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:11.309262057Z", + "id": "1255", + "owner": "kava17wpx9k6zhmlryp6y9ylj2gameuvn8gjcx2tvgj", + "principal": { + "amount": "11509616", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "5551", + "denom": "usdx" + }, + "collateral": { + "amount": "255146000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "1257", + "owner": "kava1584lapcfysyezhg80t8ptajctr8kaq7mtc4e0q", + "principal": { + "amount": "10004650", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "4064", + "denom": "usdx" + }, + "collateral": { + "amount": "499999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:36.711042819Z", + "id": "1258", + "owner": "kava1vmressd4gu3lmg9tfwe9uw0dy4gy5egsrcuqxj", + "principal": { + "amount": "60036372", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "15830", + "denom": "usdx" + }, + "collateral": { + "amount": "166384750", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:03:21.52930318Z", + "id": "1259", + "owner": "kava1gk63zjv594rmmdyecuegfr83nzw5ekwvsamzu2", + "principal": { + "amount": "24292404", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "10979805", + "denom": "usdx" + }, + "collateral": { + "amount": "143939996000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1260", + "owner": "kava135jlpa753t434kxf4hyl4h3jas6hyc3uc0fc4c", + "principal": { + "amount": "16328602400", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "6850", + "denom": "usdx" + }, + "collateral": { + "amount": "100003609", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:59:44.393525543Z", + "id": "1261", + "owner": "kava1clqkqzccvn25cpd2e8ggh2upzh6qrh67ltl3pg", + "principal": { + "amount": "10016562", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "38726", + "denom": "usdx" + }, + "collateral": { + "amount": "2001188032", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "1263", + "owner": "kava17d6e7gar8qztzrdm5vmg2x3e5rc4srklpv02x0", + "principal": { + "amount": "128158664", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "597929", + "denom": "usdx" + }, + "collateral": { + "amount": "18359781094", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1265", + "owner": "kava15adrjuvyk62x0klyukaums95frw5usm4v6daj9", + "principal": { + "amount": "2070619195", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3732", + "denom": "usdx" + }, + "collateral": { + "amount": "99999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:43.739056413Z", + "id": "1267", + "owner": "kava13trsjpgjx4jvm6j96zxa8u4t9nf5mdddp5pwd7", + "principal": { + "amount": "10023087", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "31940", + "denom": "usdx" + }, + "collateral": { + "amount": "378586779", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1268", + "owner": "kava1j4m60f93t0fcyhf2lwvkhm2p2aswafjswv0xhd", + "principal": { + "amount": "52455626", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "20461", + "denom": "usdx" + }, + "collateral": { + "amount": "3059884500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1270", + "owner": "kava14pdjqq4v30rsndsndzyvqndqvzwwj3lt3wj066", + "principal": { + "amount": "300910369", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "281287", + "denom": "usdx" + }, + "collateral": { + "amount": "4956406298", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1274", + "owner": "kava1ku2nd6z0c3nst0z8xq8er75alrph6t0tfuyylv", + "principal": { + "amount": "551512846", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "214304", + "denom": "usdx" + }, + "collateral": { + "amount": "4999961500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1276", + "owner": "kava1u8nnfm338cu7vq7pkt0hnuqdh6w255pg6fse7q", + "principal": { + "amount": "400000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "6734", + "denom": "usdx" + }, + "collateral": { + "amount": "89918663", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "1277", + "owner": "kava1hhppzv49v3ykpw94euytxg7xp22wddmnfaas8f", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "118090", + "denom": "usdx" + }, + "collateral": { + "amount": "1736726669", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "1278", + "owner": "kava1zmmrqremnqj4j8y6cm8cg3av6chp5f5tpyxuwq", + "principal": { + "amount": "200000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "6848", + "denom": "usdx" + }, + "collateral": { + "amount": "95991124", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:11.309262057Z", + "id": "1279", + "owner": "kava1rm4kcra7njawz0cm8uamxddu2n4uelykq5lv8r", + "principal": { + "amount": "10586805", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "24555", + "denom": "usdx" + }, + "collateral": { + "amount": "1589999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "1281", + "owner": "kava1xu4ft9ul3jh9khrjt69rhmt6pfd3jtea0wstv8", + "principal": { + "amount": "172034751", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "5506", + "denom": "usdx" + }, + "collateral": { + "amount": "593041575", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:27.75505786Z", + "id": "1282", + "owner": "kava174pvmplhj38tjy45qqlfhzmkyldljg6r755dna", + "principal": { + "amount": "86587423", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3681", + "denom": "usdx" + }, + "collateral": { + "amount": "800000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:59:44.393525543Z", + "id": "1283", + "owner": "kava1yn80gd43m0m329gsxwml3qcmu07gh4qczfufmn", + "principal": { + "amount": "10008864", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "406", + "denom": "usdx" + }, + "collateral": { + "amount": "103128000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:00:08.102456799Z", + "id": "1286", + "owner": "kava1zyrpqcgl3aeyp2vn0e5y43sskwvqjlqazlzgcv", + "principal": { + "amount": "11011298", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "6623", + "denom": "usdx" + }, + "collateral": { + "amount": "69999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "1287", + "owner": "kava1pz23zc6stea4ctl5jrclxpzzq3ftfgxslxvlqg", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "28932", + "denom": "usdx" + }, + "collateral": { + "amount": "499961500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:43.739056413Z", + "id": "1289", + "owner": "kava1yf7s5puv3fwv0jlxqk45x5mzl893ellcyly4wd", + "principal": { + "amount": "45000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "6551", + "denom": "usdx" + }, + "collateral": { + "amount": "99961500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "1292", + "owner": "kava1uqm720kpl45qhvkttz5ul46qzgch7ltg0wc32j", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "433520", + "denom": "usdx" + }, + "collateral": { + "amount": "5249999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1297", + "owner": "kava12649nuzxgmd374s9umfq36ty20e8exqycznuuv", + "principal": { + "amount": "845000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "6106", + "denom": "usdx" + }, + "collateral": { + "amount": "92209000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:18.15526764Z", + "id": "1301", + "owner": "kava1unhe2nyn6klp0q2lucy7d02h0ln2etvcs624ha", + "principal": { + "amount": "10311548", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3607", + "denom": "usdx" + }, + "collateral": { + "amount": "101191500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:43.739056413Z", + "id": "1302", + "owner": "kava1sfzcujgrda8psrhrwmnsyr50zla3eht0fkatuv", + "principal": { + "amount": "10030813", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "941", + "denom": "usdx" + }, + "collateral": { + "amount": "81294500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:59:00.929004542Z", + "id": "1305", + "owner": "kava1luqjeckzr9ylzj2jpl2gtaxlr2j7d7sn2ssznf", + "principal": { + "amount": "10349166", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "7059", + "denom": "usdx" + }, + "collateral": { + "amount": "98723000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:03:28.737551656Z", + "id": "1306", + "owner": "kava1cx4d9mz9vyt7806wqqm3q7nzj4pd4nzvn8v25v", + "principal": { + "amount": "11000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "15817", + "denom": "usdx" + }, + "collateral": { + "amount": "257330113", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:03:28.737551656Z", + "id": "1317", + "owner": "kava10aan0klyyxuvv5tdgrghf85agzq76uy0n2a7l5", + "principal": { + "amount": "26074179", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "8015", + "denom": "usdx" + }, + "collateral": { + "amount": "118659605", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:14.400991279Z", + "id": "1319", + "owner": "kava1969cxuzxhdsk8cn0anspwdlk2l5scrm0dqlhpy", + "principal": { + "amount": "13895247", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "49121", + "denom": "usdx" + }, + "collateral": { + "amount": "771678715", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:27.75505786Z", + "id": "1320", + "owner": "kava1hyeh8p3gk5y4s55eazr9r0fd4yjf3fkgfgfj2a", + "principal": { + "amount": "85866795", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "6707", + "denom": "usdx" + }, + "collateral": { + "amount": "109998000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:00:44.590106804Z", + "id": "1322", + "owner": "kava1kp4x2u06esxzjkp3fhkwf6ap6g0ne4348z8vj0", + "principal": { + "amount": "11236877", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "45210926", + "denom": "usdx" + }, + "collateral": { + "amount": "1030250000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1323", + "owner": "kava1lrrzm6celm0hp9nkm27etlyq0tp74szn2wdfg8", + "principal": { + "amount": "82000000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "8857", + "denom": "usdx" + }, + "collateral": { + "amount": "137488944", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:34.296774744Z", + "id": "1324", + "owner": "kava1hfp6htzwlryl3kpuc2cd3wu2my47pr3t7ndj2k", + "principal": { + "amount": "15138783", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "5611", + "denom": "usdx" + }, + "collateral": { + "amount": "98043000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "1328", + "owner": "kava17n2afhpwfr8avv47ga07sdfw7vl46r2y5fz5zj", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "5610", + "denom": "usdx" + }, + "collateral": { + "amount": "185530000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "1329", + "owner": "kava1x8cy4tfcxzywqwenttjswlv6x8swhc6hz2xfxq", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "11871", + "denom": "usdx" + }, + "collateral": { + "amount": "313356363", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:43.897016316Z", + "id": "1340", + "owner": "kava180925d4xdvu7xzrsnxajylj72zccxunzjnmsem", + "principal": { + "amount": "44429544", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "4038", + "denom": "usdx" + }, + "collateral": { + "amount": "110000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:20.453076633Z", + "id": "1345", + "owner": "kava1xg0ktvzyqq7z6nx57e4yhfzsxxwh9nft5xyh8j", + "principal": { + "amount": "10631800", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "13626", + "denom": "usdx" + }, + "collateral": { + "amount": "376061500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:05.765073985Z", + "id": "1349", + "owner": "kava1puk39x7klt3yk3mc8p6s4rzx55m2qneck39dny", + "principal": { + "amount": "36557144", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "4146", + "denom": "usdx" + }, + "collateral": { + "amount": "108163287", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:59:14.765283053Z", + "id": "1351", + "owner": "kava1m58kxv9ecjgz4nfn2hjfsqd7m0ymk2rn0u9d5j", + "principal": { + "amount": "11881412", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "17899", + "denom": "usdx" + }, + "collateral": { + "amount": "509465880", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "1352", + "owner": "kava1w2h89j6vp4520nhl3ap23xxvwv65vtj07nh5kt", + "principal": { + "amount": "50000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3326", + "denom": "usdx" + }, + "collateral": { + "amount": "68051902", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "1355", + "owner": "kava1v4cpsf2tzygdzvmyqza9fz5mglc0h6fmvcn4ad", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3449", + "denom": "usdx" + }, + "collateral": { + "amount": "59999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "1357", + "owner": "kava1vxycqlk4wjgw759jy85w3fd9ggv02sy0jnr5xl", + "principal": { + "amount": "10001374", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3700", + "denom": "usdx" + }, + "collateral": { + "amount": "99999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "1358", + "owner": "kava1na8wk7yu8tp7zafyhaujwywv8gvz0vn8g7ryx8", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "9277", + "denom": "usdx" + }, + "collateral": { + "amount": "319997000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:43.739056413Z", + "id": "1359", + "owner": "kava1se0fn725w2tk2rvqun02wnc70jmaret6xt0ymz", + "principal": { + "amount": "30394076", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "82156", + "denom": "usdx" + }, + "collateral": { + "amount": "3209723000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "1360", + "owner": "kava1hu4d2xcerckx35pl4cpkl55guhs06sgcja0er0", + "principal": { + "amount": "327961260", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1214", + "denom": "usdx" + }, + "collateral": { + "amount": "89209600", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:58:40.320250584Z", + "id": "1361", + "owner": "kava1t0l6gx3tz5jeqdqzgkl7xcy4arhn2cskgfurgc", + "principal": { + "amount": "10142053", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "7735", + "denom": "usdx" + }, + "collateral": { + "amount": "147617845", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "1363", + "owner": "kava1qq9ustlc0nv4aew275w93g4qy5zahqgxf5mwv9", + "principal": { + "amount": "21749277", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "18792", + "denom": "usdx" + }, + "collateral": { + "amount": "550364145", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:36.711042819Z", + "id": "1364", + "owner": "kava1wk6swqywa5esnnp0wyvhxy7j72rt9gn4t9ma8r", + "principal": { + "amount": "54305931", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "5611", + "denom": "usdx" + }, + "collateral": { + "amount": "230000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:00:53.396708352Z", + "id": "1372", + "owner": "kava1v9yhqm95fzhxj47gn68f6vxmjvt5gy9csgzuw8", + "principal": { + "amount": "16000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "32934", + "denom": "usdx" + }, + "collateral": { + "amount": "999961500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1380", + "owner": "kava1730sscuel2mu4el3y7hq7ee5u4m84rjlwr5msw", + "principal": { + "amount": "100000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2501", + "denom": "usdx" + }, + "collateral": { + "amount": "112246039", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:18.15526764Z", + "id": "1383", + "owner": "kava1tanhljwuka9lurdvxwzp3y625pt8zxdjaxqf8a", + "principal": { + "amount": "12339167", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3679", + "denom": "usdx" + }, + "collateral": { + "amount": "102627192", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:05.765073985Z", + "id": "1384", + "owner": "kava1f7dcpepswwk0l77rwmgatdncdpw0drruaaagp7", + "principal": { + "amount": "10558024", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3070675", + "denom": "usdx" + }, + "collateral": { + "amount": "499799723000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1399", + "owner": "kava1snaq99cvtjzcu9uagtw5j7guu62gpr75q0cvh5", + "principal": { + "amount": "42077128822", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2893", + "denom": "usdx" + }, + "collateral": { + "amount": "63640000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:55.262259649Z", + "id": "1400", + "owner": "kava1y5gg3wpwymdz90c9crz8jnar0clzw79znl7rmg", + "principal": { + "amount": "10000895", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "384", + "denom": "usdx" + }, + "collateral": { + "amount": "150000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "1403", + "owner": "kava1fyw7yxxjw535cudc270wcj3ea3fyn8p9pu6qvd", + "principal": { + "amount": "10004401", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "64919", + "denom": "usdx" + }, + "collateral": { + "amount": "2099998000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "1410", + "owner": "kava1n20rxrt3a4mlslnhjk8n4edlh7fpzy438cv48m", + "principal": { + "amount": "275000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "11287", + "denom": "usdx" + }, + "collateral": { + "amount": "249999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:27.75505786Z", + "id": "1413", + "owner": "kava14cgufq9dxenj2wpvu6f28w2pvgz472zcfd54jd", + "principal": { + "amount": "33791979", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "116717", + "denom": "usdx" + }, + "collateral": { + "amount": "4548884643", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1414", + "owner": "kava16cg0hgegyy4z6kph2zmp92vklrjex4veta96s0", + "principal": { + "amount": "439189808", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3397", + "denom": "usdx" + }, + "collateral": { + "amount": "94998000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "1415", + "owner": "kava1e726rq39ue8yk9kr67lpv2cfd58dyfylwtqxfn", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "6949", + "denom": "usdx" + }, + "collateral": { + "amount": "211550255", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:31.545909484Z", + "id": "1420", + "owner": "kava1fdzpv9rrn8gvsxg8adp2kwyqnwuyxezjy742j2", + "principal": { + "amount": "24035572", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "258180", + "denom": "usdx" + }, + "collateral": { + "amount": "11435775702", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1429", + "owner": "kava1hfmlqt5qxatfzh3jnyx55ztl050ev7u6l9qefq", + "principal": { + "amount": "1162761534", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "294426", + "denom": "usdx" + }, + "collateral": { + "amount": "14319113251", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1440", + "owner": "kava1m3r9maghhlky9sdwrgt6z532r4sskz8399zvr9", + "principal": { + "amount": "1400000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "123580", + "denom": "usdx" + }, + "collateral": { + "amount": "4767052472", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1445", + "owner": "kava13yncpezqz9j5gyl64l5f2rd7k7dtr2eaa0gtwg", + "principal": { + "amount": "487130358", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "491770", + "denom": "usdx" + }, + "collateral": { + "amount": "18754089441", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1449", + "owner": "kava1mwc52eye7u8n4fqllt5jzp762clqgkzd655mxx", + "principal": { + "amount": "1942384912", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3875", + "denom": "usdx" + }, + "collateral": { + "amount": "136124159", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1454", + "owner": "kava1vd5fqxnnc0e7p0jr8sggwd4sfcz78ahtswu2ve", + "principal": { + "amount": "12762813", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2985", + "denom": "usdx" + }, + "collateral": { + "amount": "1000000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "1462", + "owner": "kava1c547d5ewazfzv0d7xdk03yfg8fvrpm07wn00e0", + "principal": { + "amount": "10000078", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "356178", + "denom": "usdx" + }, + "collateral": { + "amount": "15000000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1476", + "owner": "kava1e2pmq54dyq8xzdq6n9dnquvt0ux3mu2n56wqgg", + "principal": { + "amount": "2000164615", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "25597", + "denom": "usdx" + }, + "collateral": { + "amount": "900000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:36.711042819Z", + "id": "1481", + "owner": "kava1uy3fnhxlqnady9rfx3h9uc35xtnx0u94eh744w", + "principal": { + "amount": "91822091", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "521", + "denom": "usdx" + }, + "collateral": { + "amount": "97849489", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:02:09.942783911Z", + "id": "1487", + "owner": "kava1td0y8y9m7tjmq59v0uykjjrpdj2mq0y5h28keu", + "principal": { + "amount": "10009848", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2908", + "denom": "usdx" + }, + "collateral": { + "amount": "559315359", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:00.399199333Z", + "id": "1503", + "owner": "kava1wzegq9jk7pa8zysckmjth2wevynd2a2k0ywc35", + "principal": { + "amount": "10003128", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "12424", + "denom": "usdx" + }, + "collateral": { + "amount": "399768953", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:43.897016316Z", + "id": "1513", + "owner": "kava1cl2ssjt2w6jd4ur5ucwr39pecyst6h0jxh9v38", + "principal": { + "amount": "48623068", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2936", + "denom": "usdx" + }, + "collateral": { + "amount": "110000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:03:36.027198424Z", + "id": "1518", + "owner": "kava18awfuum2mk0f62trzmlznw3q3qhxf9ggqf6qwf", + "principal": { + "amount": "10226655", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "50416", + "denom": "usdx" + }, + "collateral": { + "amount": "5000423699", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1533", + "owner": "kava1t2u6mhqng5tkwkvjkj8fcp7szq2lkaffydwh2j", + "principal": { + "amount": "750942955", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "419485", + "denom": "usdx" + }, + "collateral": { + "amount": "46289722000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1535", + "owner": "kava1mwxyxveamzwkxtnwkvcftlp4ulgexx4msuyvgr", + "principal": { + "amount": "6801183091", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2736", + "denom": "usdx" + }, + "collateral": { + "amount": "71369000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:09.136574316Z", + "id": "1544", + "owner": "kava1066l6vw7kycx8tmesp8y4mtmphmptc0hw88wj8", + "principal": { + "amount": "10011526", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "32073", + "denom": "usdx" + }, + "collateral": { + "amount": "3772564386", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1553", + "owner": "kava1d6lk9aug3rq6wr57rzc54vstus67amgsxvxkhv", + "principal": { + "amount": "510000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1092", + "denom": "usdx" + }, + "collateral": { + "amount": "124769150", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:00:31.529977202Z", + "id": "1555", + "owner": "kava1alt4u48umfqgx6uwuhvu5qts67t78p86ejlv5y", + "principal": { + "amount": "12074329", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "81983", + "denom": "usdx" + }, + "collateral": { + "amount": "3999961500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1562", + "owner": "kava184f7d6lwrd2esrmuvqfqrln7crv5n7vu07zq27", + "principal": { + "amount": "404589560", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "102821", + "denom": "usdx" + }, + "collateral": { + "amount": "5499999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1567", + "owner": "kava1p4e6fdztuwz8ukctfg7hxth0x5rump93kvy4kg", + "principal": { + "amount": "547482900", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2576", + "denom": "usdx" + }, + "collateral": { + "amount": "100068357", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:59:44.393525543Z", + "id": "1568", + "owner": "kava1jplrqjhj2x7khpr3ppzmn202yq5exhm3hl2aj5", + "principal": { + "amount": "10011257", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "21951", + "denom": "usdx" + }, + "collateral": { + "amount": "999999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:36.711042819Z", + "id": "1570", + "owner": "kava1a5vvwsfmnehh5ng73w8v3xvhch6dm60xjzg2xf", + "principal": { + "amount": "92509351", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "6255", + "denom": "usdx" + }, + "collateral": { + "amount": "249999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:43.739056413Z", + "id": "1573", + "owner": "kava1xr2csjw6h8z4tawqeqcswvpq5p78rgpgurc20d", + "principal": { + "amount": "25495262", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2145216", + "denom": "usdx" + }, + "collateral": { + "amount": "198549789414", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1575", + "owner": "kava1rs8hkzyescwe3kqfu0dcqw2zd7td24ekywaxre", + "principal": { + "amount": "33741132696", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2324", + "denom": "usdx" + }, + "collateral": { + "amount": "200000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T18:58:31.264015933Z", + "id": "1580", + "owner": "kava1ksqqkkryqewvcddz9j02sgvnxrh75c5hg35t6e", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "16576", + "denom": "usdx" + }, + "collateral": { + "amount": "2000000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1583", + "owner": "kava1xwkrx4ytz6vsa5d3pc0pcsyr6twuwfdwap2vvy", + "principal": { + "amount": "300046458", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "12014", + "denom": "usdx" + }, + "collateral": { + "amount": "534010481", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:05.765073985Z", + "id": "1584", + "owner": "kava1pzdsm4chkg4nwvj7lxrsx20s5r4va74y6z3jzs", + "principal": { + "amount": "54597037", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "39318", + "denom": "usdx" + }, + "collateral": { + "amount": "1500000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "1585", + "owner": "kava1vl99a0xpmm4dg6epd7snjgxpzqe4px7e3v4mel", + "principal": { + "amount": "202532612", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2504", + "denom": "usdx" + }, + "collateral": { + "amount": "200000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:50.915130002Z", + "id": "1590", + "owner": "kava1wefhhne7mr65dr9vw0qgdp7wu22zv0j2sghd75", + "principal": { + "amount": "20000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "22168", + "denom": "usdx" + }, + "collateral": { + "amount": "700861500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:50.815581672Z", + "id": "1593", + "owner": "kava1hqsy9e39zp2dla42cy8lj7y6ylzu8y8xjmr0wq", + "principal": { + "amount": "115144874", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2121", + "denom": "usdx" + }, + "collateral": { + "amount": "100542131", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "1594", + "owner": "kava12yhn75au348gl32u0vtcn529rxqysjlenxpx2t", + "principal": { + "amount": "10291858", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "839", + "denom": "usdx" + }, + "collateral": { + "amount": "69999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1596", + "owner": "kava1lc4dwgtnaynd765zdkmn9a3p4vu2yn442u5e9n", + "principal": { + "amount": "10068403", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "23616", + "denom": "usdx" + }, + "collateral": { + "amount": "1229241373", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1597", + "owner": "kava19dtn5apvmrytsma7nmq4tqfyh8js4npv6tculu", + "principal": { + "amount": "124973171", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "10444", + "denom": "usdx" + }, + "collateral": { + "amount": "528561869", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:36.711042819Z", + "id": "1599", + "owner": "kava17c3w0dcyrpwemfhu25ds59vjum0d58fwxgf6h8", + "principal": { + "amount": "54399556", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "13363", + "denom": "usdx" + }, + "collateral": { + "amount": "817998000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:14.400991279Z", + "id": "1671", + "owner": "kava12nwz55p7g29wn5hg44g5ljp9rrsvufdt2v0a6y", + "principal": { + "amount": "77728523", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "39364", + "denom": "usdx" + }, + "collateral": { + "amount": "1949999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "1682", + "owner": "kava1tkz0j7v8x3qe6u8tvfda8kz00747ntgxlglzl4", + "principal": { + "amount": "251000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "8111", + "denom": "usdx" + }, + "collateral": { + "amount": "482061500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "1689", + "owner": "kava1sdygaq5q4mkq2gtdr2q6ex6c79lw4dn928smcd", + "principal": { + "amount": "45421395", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "877940", + "denom": "usdx" + }, + "collateral": { + "amount": "50984997000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1690", + "owner": "kava17hgvly0hyqgdktkg7k34pqx0nst3t0rguy62ta", + "principal": { + "amount": "5303396675", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "232585", + "denom": "usdx" + }, + "collateral": { + "amount": "15740079851", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1696", + "owner": "kava1qxprregw2tvclv5ecg23u8cm8vwx500aqwcp5g", + "principal": { + "amount": "1611503717", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "5289", + "denom": "usdx" + }, + "collateral": { + "amount": "379961500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:05.765073985Z", + "id": "1697", + "owner": "kava1qhhhgn6va38sw55p2eawyccl2ljpmk7zdlar84", + "principal": { + "amount": "30000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "144389", + "denom": "usdx" + }, + "collateral": { + "amount": "11099000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1713", + "owner": "kava1h2z0dvaapp99935p6khak42js7xychup072l0a", + "principal": { + "amount": "1129954884", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "47553579", + "denom": "usdx" + }, + "collateral": { + "amount": "2811987457763", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1719", + "owner": "kava1x242qk6jf2rv23ruvk6fmxp97gg2y75a9r2caq", + "principal": { + "amount": "347896919862", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "6497923", + "denom": "usdx" + }, + "collateral": { + "amount": "316999999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1731", + "owner": "kava10wyahu4d23fgtzjdxc998gn7z48lc2nte79z37", + "principal": { + "amount": "40000000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "617350", + "denom": "usdx" + }, + "collateral": { + "amount": "49999860500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1738", + "owner": "kava1jvxu04elz2lklea8sv36lk0x973hrwr4mu9lt2", + "principal": { + "amount": "5000226556", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1498", + "denom": "usdx" + }, + "collateral": { + "amount": "100000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:55.262259649Z", + "id": "1751", + "owner": "kava1v5jwfer6xe67yvp844paw8alj6x7w080gc8hpf", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1625", + "denom": "usdx" + }, + "collateral": { + "amount": "100000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:31.545909484Z", + "id": "1753", + "owner": "kava14tex78srs63fk436kef8d3wct0wqjh2ttzdk8y", + "principal": { + "amount": "11406546", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "4212", + "denom": "usdx" + }, + "collateral": { + "amount": "500000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:05.765073985Z", + "id": "1760", + "owner": "kava1g9r25c4t2fcq9pett9x89758gyw3hjhydg7y5u", + "principal": { + "amount": "80002346", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1670388", + "denom": "usdx" + }, + "collateral": { + "amount": "159200000500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1761", + "owner": "kava1ehtxa3cy5s5ulksfswx5c7umftlm0p2yrnc6vd", + "principal": { + "amount": "26000579502", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1391", + "denom": "usdx" + }, + "collateral": { + "amount": "99999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:55.262259649Z", + "id": "1765", + "owner": "kava1wnpxrmcn8nu9skukt7fzwyr98f3x059kt35v3p", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1379", + "denom": "usdx" + }, + "collateral": { + "amount": "112221184", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:55.262259649Z", + "id": "1769", + "owner": "kava1h6eea690v3nug322wqjmgmrt0uxatg2zuz6tt9", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "13926", + "denom": "usdx" + }, + "collateral": { + "amount": "1200261500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:36.711042819Z", + "id": "1777", + "owner": "kava16utunjj9df9p2dkahdg2hs2e0qasz4rh84lhrp", + "principal": { + "amount": "110000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2298", + "denom": "usdx" + }, + "collateral": { + "amount": "145000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:20.453076633Z", + "id": "1778", + "owner": "kava1xjh3cd48kgpgmgc7n3tp08v5d3xqp6vck3drcx", + "principal": { + "amount": "17000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1055804", + "denom": "usdx" + }, + "collateral": { + "amount": "60640062996", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1783", + "owner": "kava1e4fl4ht4696v274pp4dzm9fkwe6f2rfqv6q6wq", + "principal": { + "amount": "8510993662", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "271428", + "denom": "usdx" + }, + "collateral": { + "amount": "50000084500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1798", + "owner": "kava1lfjqvzynrwvul3nrv8dxme3l38896nlx6f0xkw", + "principal": { + "amount": "7010904939", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "4016", + "denom": "usdx" + }, + "collateral": { + "amount": "405861500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:02.663985461Z", + "id": "1808", + "owner": "kava179tps3eucdmh409hsld8z3pgfq94lyr74m2jxc", + "principal": { + "amount": "40000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "4735005", + "denom": "usdx" + }, + "collateral": { + "amount": "400099960500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1816", + "owner": "kava1nr3a995c3ywl8d4cplczsavvtfd5qhetffypd2", + "principal": { + "amount": "48379214253", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "248", + "denom": "usdx" + }, + "collateral": { + "amount": "100000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:04:09.136574316Z", + "id": "1817", + "owner": "kava12ljyewdkrpnch8z4yy8wtepr2esl8e93fwc47f", + "principal": { + "amount": "10421985", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "48495", + "denom": "usdx" + }, + "collateral": { + "amount": "11599999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1823", + "owner": "kava13cr8f7s0zgvd0365mq6nzsegtjjpfn3t9frcgj", + "principal": { + "amount": "1234240276", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1288", + "denom": "usdx" + }, + "collateral": { + "amount": "99900000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:50.815581672Z", + "id": "1829", + "owner": "kava1zhvexd6vrfh9uem3q25xmz40pje5p59uh5dc2q", + "principal": { + "amount": "15000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "650559", + "denom": "usdx" + }, + "collateral": { + "amount": "90000000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1833", + "owner": "kava1hs8f5ya5ckzxnqg5aumagml2ttkfx968h45hev", + "principal": { + "amount": "10000000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "30428", + "denom": "usdx" + }, + "collateral": { + "amount": "3810764342", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1838", + "owner": "kava1ucek4at0fx5pzlvraymv773shy36qsdw5w035c", + "principal": { + "amount": "459578180", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2246", + "denom": "usdx" + }, + "collateral": { + "amount": "281159211", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:43.739056413Z", + "id": "1843", + "owner": "kava1j0yxk0dhfhfcyppcadt32h5jcf2pvncuz833q8", + "principal": { + "amount": "30311314", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "134377", + "denom": "usdx" + }, + "collateral": { + "amount": "31089999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1849", + "owner": "kava19p7kkswphk6qv5ymvj5385aq7dc7gxpzsgaa0r", + "principal": { + "amount": "3000001696", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2075", + "denom": "usdx" + }, + "collateral": { + "amount": "355000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:03:59.168880771Z", + "id": "1850", + "owner": "kava1cn0chmv0dt8vg9xrhj0jadc9yqx203cj3s2c9q", + "principal": { + "amount": "30511527", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "28527", + "denom": "usdx" + }, + "collateral": { + "amount": "5399785500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1851", + "owner": "kava1rle08y653c80s9rwmpuxq9nyq5lg9c47l2m4qs", + "principal": { + "amount": "600000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "375836", + "denom": "usdx" + }, + "collateral": { + "amount": "39944954979", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1852", + "owner": "kava1zrthvpd9rjmyapya6xxf2ywrs4h3ugfmfw4rzu", + "principal": { + "amount": "5939178403", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "33600", + "denom": "usdx" + }, + "collateral": { + "amount": "150924040934", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1860", + "owner": "kava17jpu5g2du2p0pmnq8meakcur6vm8rwezv4tn9z", + "principal": { + "amount": "21073443850", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1295", + "denom": "usdx" + }, + "collateral": { + "amount": "235274163", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "1863", + "owner": "kava10tg5kv6rhm3h2ufavh0y3qmphvmvmejs8l53as", + "principal": { + "amount": "24000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "823", + "denom": "usdx" + }, + "collateral": { + "amount": "99961500", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:20.647451252Z", + "id": "1864", + "owner": "kava1ch8equdqp9k8u87nvu5c86qvscv3p9n480g84s", + "principal": { + "amount": "15229042", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2910", + "denom": "usdx" + }, + "collateral": { + "amount": "550000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:50.815581672Z", + "id": "1865", + "owner": "kava1lm5pc2kc4zjd3gyycm9zgjv3pcfg64ld39lgp6", + "principal": { + "amount": "56551400", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "1460", + "denom": "usdx" + }, + "collateral": { + "amount": "312459006", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:05.765073985Z", + "id": "1867", + "owner": "kava1chk4a3v96nhc5msc5f84f66ulujz7xdz9fh367", + "principal": { + "amount": "30000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "974", + "denom": "usdx" + }, + "collateral": { + "amount": "200000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:50.915130002Z", + "id": "1871", + "owner": "kava1dz5zhsa0uxw62y06mwmaazgkhgq49e7sun6nf3", + "principal": { + "amount": "20000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "973", + "denom": "usdx" + }, + "collateral": { + "amount": "200000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "1872", + "owner": "kava1ha8cwpay5l293clga0sy0ersm8tqmv0gfgaejc", + "principal": { + "amount": "20000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "637", + "denom": "usdx" + }, + "collateral": { + "amount": "119723000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:01:20.647451252Z", + "id": "1878", + "owner": "kava1p45l37x9k3dsn8wuf90wcqxg8498y3ha54ju9a", + "principal": { + "amount": "15215793", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3713", + "denom": "usdx" + }, + "collateral": { + "amount": "900000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1881", + "owner": "kava1u0h3m6s9cn4t7lcemt5yplz2r5f8pvt78t300w", + "principal": { + "amount": "102976435", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "3761", + "denom": "usdx" + }, + "collateral": { + "amount": "999999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:36.711042819Z", + "id": "1883", + "owner": "kava1peyjt72c2dk4ge7gavl56amvqxzukjyu7qth3s", + "principal": { + "amount": "106104803", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "991", + "denom": "usdx" + }, + "collateral": { + "amount": "200000000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:43.739056413Z", + "id": "1891", + "owner": "kava1etzj0qsu36dfyxa44r2pwz6am5un99ge7ee2aq", + "principal": { + "amount": "33000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "480", + "denom": "usdx" + }, + "collateral": { + "amount": "249571613", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:06:36.711042819Z", + "id": "1895", + "owner": "kava1lf86aj2akcrt5ehtvfgnhlrlj442z676usk9ly", + "principal": { + "amount": "18000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "367", + "denom": "usdx" + }, + "collateral": { + "amount": "147998000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:05:28.231878135Z", + "id": "1896", + "owner": "kava1t4ctv6vzg77qwrprdzjs22rxcg8wc3usscjvnx", + "principal": { + "amount": "14881392", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "6214", + "denom": "usdx" + }, + "collateral": { + "amount": "2809484751", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1897", + "owner": "kava1efqg07y6eyrt3x80fcsdv99kj2ezya7pntjutl", + "principal": { + "amount": "308256156", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "2521", + "denom": "usdx" + }, + "collateral": { + "amount": "899999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "1901", + "owner": "kava10fu8zc5qtw2wa50z244cnlxxa3pjs8el0hc8p0", + "principal": { + "amount": "126721986", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "67", + "denom": "usdx" + }, + "collateral": { + "amount": "199999000", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "1916", + "owner": "kava1xcku3nqxm5jt7fhgrk9pvpdqqfjkxlwx2m8aka", + "principal": { + "amount": "30000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "389", + "denom": "usdx" + }, + "collateral": { + "amount": "2144242904", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "1917", + "owner": "kava1p063qu3kh40ruw7ytwmayj7q5lreaq9skyett9", + "principal": { + "amount": "200000000", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "268", + "denom": "usdx" + }, + "collateral": { + "amount": "3488776197", + "denom": "bnb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "1918", + "owner": "kava1p2kvztny6e4ffttdp2kmwlzg33zpu8n4cdza0v", + "principal": { + "amount": "383224939", + "denom": "usdx" + }, + "type": "bnb-a" + }, + { + "accumulated_fees": { + "amount": "134224", + "denom": "usdx" + }, + "collateral": { + "amount": "1002498", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1365", + "owner": "kava1gzc54u4p67hh9r4m9vcml3ke9fc29tplvvaev3", + "principal": { + "amount": "49698010", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "1060209", + "denom": "usdx" + }, + "collateral": { + "amount": "7929738", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1370", + "owner": "kava1r7uckqzflqdqcwllh3ty36qvzl0z7utv5ujh3l", + "principal": { + "amount": "350558245", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "50672", + "denom": "usdx" + }, + "collateral": { + "amount": "279998", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "1374", + "owner": "kava1vlpsrmdyuywvaqrv7rx6xga224sqfwz3fyfhwq", + "principal": { + "amount": "16426909", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "82258757", + "denom": "usdx" + }, + "collateral": { + "amount": "1208494457", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1376", + "owner": "kava1wjjg0mvsfgnskjj7qq28uaxqwq5h38q6nh5ah8", + "principal": { + "amount": "130283397131", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "1228368", + "denom": "usdx" + }, + "collateral": { + "amount": "9999998", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1388", + "owner": "kava179ahnk902wgm7qzr66t5ga0a8euc28ce703jy3", + "principal": { + "amount": "400000000", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "6039644", + "denom": "usdx" + }, + "collateral": { + "amount": "35097117", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1396", + "owner": "kava1acqutt8qfe66c0nnhlzl7rmadfnuxnuaetehfh", + "principal": { + "amount": "1810000000", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "2134481", + "denom": "usdx" + }, + "collateral": { + "amount": "10086310", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1401", + "owner": "kava1tzzdns8zkl0qptywnpr27eh0evj9zu45pc8f0g", + "principal": { + "amount": "802718857", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "18785911", + "denom": "usdx" + }, + "collateral": { + "amount": "91840786", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1406", + "owner": "kava1vrc7zv2epn6es9whxycava8uwta9ncax8wuw6l", + "principal": { + "amount": "6255166514", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "29514", + "denom": "usdx" + }, + "collateral": { + "amount": "131316", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:06:43.897016316Z", + "id": "1408", + "owner": "kava18a8gwg9kz0efhww629h99cclwyywrwrf97l669", + "principal": { + "amount": "10065789", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "3799682", + "denom": "usdx" + }, + "collateral": { + "amount": "19999994", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1409", + "owner": "kava15jtcnhucatrg8z70s5huxpyhnwf2klupv6xqyq", + "principal": { + "amount": "1400000000", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "62", + "denom": "usdx" + }, + "collateral": { + "amount": "109058", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:06:43.897016316Z", + "id": "1418", + "owner": "kava1w4umquan7w2v3n3enh6ap854vk4a58kftnq4au", + "principal": { + "amount": "10749100", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "54445", + "denom": "usdx" + }, + "collateral": { + "amount": "282155", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "1419", + "owner": "kava1e726rq39ue8yk9kr67lpv2cfd58dyfylwtqxfn", + "principal": { + "amount": "18000000", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "337088", + "denom": "usdx" + }, + "collateral": { + "amount": "80948774", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1422", + "owner": "kava1rea6zxqq78klh7uhf78juqp9nmtl53j7hsnquk", + "principal": { + "amount": "9441429321", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "2075376", + "denom": "usdx" + }, + "collateral": { + "amount": "36567486", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1423", + "owner": "kava1lmdqakjz5p7gjw3q7333kkgc2xje4d6zzu544k", + "principal": { + "amount": "3489316784", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "8020344", + "denom": "usdx" + }, + "collateral": { + "amount": "36768000", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1424", + "owner": "kava10l6gr3u8xqfd8jps724n4hkhd92fh9rugyx2n7", + "principal": { + "amount": "3200000000", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "251626", + "denom": "usdx" + }, + "collateral": { + "amount": "2499996", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1426", + "owner": "kava1naekqn8vfcxdrge0qmajf0t8uatamf6lhd4w6x", + "principal": { + "amount": "170230504", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "34853", + "denom": "usdx" + }, + "collateral": { + "amount": "449444", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1450", + "owner": "kava12ltf567h50jf3juw3a9m996fwe5jyma676l0gw", + "principal": { + "amount": "30554777", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "803610", + "denom": "usdx" + }, + "collateral": { + "amount": "6630179", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1464", + "owner": "kava1ttrw6gxz9nz49gse9v0tqqa2u97s34yx4shl55", + "principal": { + "amount": "413213287", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "8277226", + "denom": "usdx" + }, + "collateral": { + "amount": "46020422", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1473", + "owner": "kava1h8fsy6u3hy77hn8gguh59qx9s6mn64rshfke2l", + "principal": { + "amount": "3500000000", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "3352958", + "denom": "usdx" + }, + "collateral": { + "amount": "14070705", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1510", + "owner": "kava182mzj3c7hg96fsaratn0wt2khgtgxgvlwhg77e", + "principal": { + "amount": "1300000000", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "497169", + "denom": "usdx" + }, + "collateral": { + "amount": "13646103", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1602", + "owner": "kava127lary0erprnrv9vn3wykyt9pjm5a5tdwdnm3h", + "principal": { + "amount": "1222609731", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "9357", + "denom": "usdx" + }, + "collateral": { + "amount": "1964000", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1605", + "owner": "kava13d3nklvf22whykz5a8vt8qlj66029gpwqcmj69", + "principal": { + "amount": "130022492", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "476201", + "denom": "usdx" + }, + "collateral": { + "amount": "151237022", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1606", + "owner": "kava1dpcgtp7hjvspg7nxpj7c7j25lnyyrau0g72jkd", + "principal": { + "amount": "14194860372", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "590520", + "denom": "usdx" + }, + "collateral": { + "amount": "499999990", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1607", + "owner": "kava1mz2vfw29fzkg4yj9wfh99nkgx46unhrxtyxqhc", + "principal": { + "amount": "55099102294", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "4067311", + "denom": "usdx" + }, + "collateral": { + "amount": "39761118", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1608", + "owner": "kava1g74prc3x3ke2250ndr8ndpkceqvzwdqzq8ddt7", + "principal": { + "amount": "4399655926", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "298815", + "denom": "usdx" + }, + "collateral": { + "amount": "7486653", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1609", + "owner": "kava1y39ev0vqwnzqr3uhm26lp0ywwjjcfsf4ylvtmy", + "principal": { + "amount": "454769246", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "511461", + "denom": "usdx" + }, + "collateral": { + "amount": "499999998", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1610", + "owner": "kava1mgw47h20dkwqv7n2u8qg9ujds208x6mrg2zza0", + "principal": { + "amount": "56348972802", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "124586", + "denom": "usdx" + }, + "collateral": { + "amount": "109999998", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1611", + "owner": "kava1y78l0cnun58rqlkj60w2wvf7a6lsc3exs5tpaj", + "principal": { + "amount": "12021625632", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "781775063", + "denom": "usdx" + }, + "collateral": { + "amount": "8920460438", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1612", + "owner": "kava10hczxv0p3eadcwgt5u79yhahsyuw98u26qan50", + "principal": { + "amount": "469000000000", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "119544", + "denom": "usdx" + }, + "collateral": { + "amount": "99999998", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1613", + "owner": "kava1n7rtcw75duvqgaylyq0lr3337dyxzcg0m3hdg0", + "principal": { + "amount": "11019825897", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "354898629", + "denom": "usdx" + }, + "collateral": { + "amount": "5332145883", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1614", + "owner": "kava1as5f599ltjc9uy5dpne9pkhzuylcdhsj7sa2du", + "principal": { + "amount": "591005056505", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "671252", + "denom": "usdx" + }, + "collateral": { + "amount": "6416466", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1617", + "owner": "kava1zuslhtgj5r8n95k833w5lttnjzuxcpjy7ql3c5", + "principal": { + "amount": "443643516", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "148322039", + "denom": "usdx" + }, + "collateral": { + "amount": "1098743033", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1618", + "owner": "kava19fqslxa2fv5wfdwh6gvpp2jwkuzkvcwv40qz89", + "principal": { + "amount": "88817933320", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "27821661", + "denom": "usdx" + }, + "collateral": { + "amount": "999999656", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1619", + "owner": "kava1a4n95kh4exg0krr4vqwdnuf2sm2zzs9ape904x", + "principal": { + "amount": "50131366853", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "13342519", + "denom": "usdx" + }, + "collateral": { + "amount": "230418504", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1623", + "owner": "kava1un2a96zhymexgdx9ujeldm2a6te9ar66n2en78", + "principal": { + "amount": "20475077053", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "90896", + "denom": "usdx" + }, + "collateral": { + "amount": "1089952", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1624", + "owner": "kava1c5lzj543l3xlz8s4s03phkkm4p0g6qg570vjys", + "principal": { + "amount": "65826085", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "8487678", + "denom": "usdx" + }, + "collateral": { + "amount": "49999998", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1626", + "owner": "kava10lhnlwlek6yg5n734jn8qukur2kjjhcw09xagl", + "principal": { + "amount": "4400000000", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "526178", + "denom": "usdx" + }, + "collateral": { + "amount": "11906816", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1627", + "owner": "kava19kncpd7la86z27snj6996u3ds5mtcmc5n864vx", + "principal": { + "amount": "1051468726", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "5864532", + "denom": "usdx" + }, + "collateral": { + "amount": "73425973", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1628", + "owner": "kava1lfdxw8lg7m4zgx5f2t3szkarypcytahfnl26n4", + "principal": { + "amount": "4996619516", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "81144", + "denom": "usdx" + }, + "collateral": { + "amount": "27500144", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1629", + "owner": "kava1a7vmnk0qfwuxq0jsek3hr798xutu24ga78s3ys", + "principal": { + "amount": "2602983970", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "2787602", + "denom": "usdx" + }, + "collateral": { + "amount": "60000476", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1631", + "owner": "kava1tnf0zwaqx76lkpaj0un36kvwhver8dmynvr6zs", + "principal": { + "amount": "4329676798", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "12096549", + "denom": "usdx" + }, + "collateral": { + "amount": "1087721334", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1632", + "owner": "kava1z9v59sdu65z4hssvhhhpnw0pz9p8y3kfgh0h3p", + "principal": { + "amount": "120894067436", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "1858401", + "denom": "usdx" + }, + "collateral": { + "amount": "39842084", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1634", + "owner": "kava1zdtnnt6e6n949h39eskp3m3jnmzsrrda9wfl7a", + "principal": { + "amount": "3766471725", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "27067608", + "denom": "usdx" + }, + "collateral": { + "amount": "500043304", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1636", + "owner": "kava15fcxcndmrhagc9zxt2jj5aapavens36tm9z7wr", + "principal": { + "amount": "46165840912", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "1560908", + "denom": "usdx" + }, + "collateral": { + "amount": "13753465", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1637", + "owner": "kava1drk0qa554p4r9t4vw20sqn84m9xz7dp2gr0kfy", + "principal": { + "amount": "1176169161", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "37939894", + "denom": "usdx" + }, + "collateral": { + "amount": "250275549", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1638", + "owner": "kava1kfrjwuur93wthdwc6kpf36lwftdzz22wxe5gae", + "principal": { + "amount": "23115000000", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "15002043", + "denom": "usdx" + }, + "collateral": { + "amount": "100009828", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1639", + "owner": "kava1y56rm72h5nm6psg2k7mxx2gjtldyme2wyt2nds", + "principal": { + "amount": "7790000000", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "3274821", + "denom": "usdx" + }, + "collateral": { + "amount": "33683436", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1641", + "owner": "kava1zaq2qevfefffrps03q7y4cky9sh5frtdjv65ug", + "principal": { + "amount": "2250000000", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "2099723", + "denom": "usdx" + }, + "collateral": { + "amount": "13212486", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1642", + "owner": "kava1z0u0efzn8llallan08kenpuj262etz9392phf4", + "principal": { + "amount": "1184000000", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "692882", + "denom": "usdx" + }, + "collateral": { + "amount": "6001646", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1643", + "owner": "kava12e7ryh3z4034zd398lwudmyvkm7hngy5xs3r4m", + "principal": { + "amount": "405141762", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "3234226", + "denom": "usdx" + }, + "collateral": { + "amount": "21736534", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1653", + "owner": "kava1fymnm880d4m03276vwwlm4xwtsswyqq07jg53s", + "principal": { + "amount": "1800000000", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "689284", + "denom": "usdx" + }, + "collateral": { + "amount": "5752908", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1657", + "owner": "kava1n7lp6a9fjc7qt0a6r2792kwcd2hghtuaul7x0w", + "principal": { + "amount": "400000000", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "7554017", + "denom": "usdx" + }, + "collateral": { + "amount": "50000658", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1658", + "owner": "kava176nfnxq2325z72jmxragelpx2jx3fme4g796pd", + "principal": { + "amount": "4000000000", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "357007", + "denom": "usdx" + }, + "collateral": { + "amount": "6454498", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1660", + "owner": "kava12ghgptqj954d7gr4uh0z5qesxaz3nffhkcam6r", + "principal": { + "amount": "550544479", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "9997737", + "denom": "usdx" + }, + "collateral": { + "amount": "80089011", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1661", + "owner": "kava1mgwduvsvt00q7ksxps3zl0945dsh3v4nz9c4rd", + "principal": { + "amount": "5309663119", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "21735519", + "denom": "usdx" + }, + "collateral": { + "amount": "493700908", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1662", + "owner": "kava1gr8e5w5n804gn3ypvvgdqx6535d6ukmmxcqps7", + "principal": { + "amount": "34035246609", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "11350", + "denom": "usdx" + }, + "collateral": { + "amount": "149828", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1663", + "owner": "kava1cekgrewfz3m0pq650zkr86pdam7zxvl2pcesnh", + "principal": { + "amount": "10227656", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "17648", + "denom": "usdx" + }, + "collateral": { + "amount": "3764647", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:06:43.897016316Z", + "id": "1668", + "owner": "kava1fpsxfx5wql5pcmmdewyy3uas5glgx899h0dcv5", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "19931", + "denom": "usdx" + }, + "collateral": { + "amount": "181318", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:06:27.75505786Z", + "id": "1670", + "owner": "kava18w6c7edz8n4testgwprr9wywp9q0lxp9sa4c26", + "principal": { + "amount": "11354562", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "86670", + "denom": "usdx" + }, + "collateral": { + "amount": "1000480", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1672", + "owner": "kava1c0xa226fh8e94k6lpsr890aw82g2zw3fq6q8r5", + "principal": { + "amount": "70153533", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "568", + "denom": "usdx" + }, + "collateral": { + "amount": "6399028", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1675", + "owner": "kava1ne7zl2v8ag6pnrnk5rwf6atdu9tw3pers3dv63", + "principal": { + "amount": "375151727", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "3334318", + "denom": "usdx" + }, + "collateral": { + "amount": "21538754", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1676", + "owner": "kava1ghhk6fd4xtvxxu4v230x4acj27c2mkxe2tu7qm", + "principal": { + "amount": "1800000000", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "8968077", + "denom": "usdx" + }, + "collateral": { + "amount": "103488267", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1677", + "owner": "kava19pfgjj5sp5vwa5gny0yqxp7v0g9tkd7h3j36w3", + "principal": { + "amount": "6003447888", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "15799", + "denom": "usdx" + }, + "collateral": { + "amount": "159996", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1678", + "owner": "kava1607mgduk5yuqsg7kyjd25jhuxk5xcyl6ar5qdm", + "principal": { + "amount": "10502905", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "29404", + "denom": "usdx" + }, + "collateral": { + "amount": "258998", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:03.818228071Z", + "id": "1681", + "owner": "kava126wg3hfgrxspmtupvyqvall5g75xr7fmxdssen", + "principal": { + "amount": "17500000", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "3062837", + "denom": "usdx" + }, + "collateral": { + "amount": "27073859", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1683", + "owner": "kava1l22dc2vjgrgwl73ef6rl6zp3uwr007ftnknpaw", + "principal": { + "amount": "2245002450", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "905708", + "denom": "usdx" + }, + "collateral": { + "amount": "51765395", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1686", + "owner": "kava13cr8f7s0zgvd0365mq6nzsegtjjpfn3t9frcgj", + "principal": { + "amount": "4096980983", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "3684759", + "denom": "usdx" + }, + "collateral": { + "amount": "149852660", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1687", + "owner": "kava1pvc7dsu4hd3l2ph4t3nlv6gs8e43ktelagwamy", + "principal": { + "amount": "9205173893", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "22940712", + "denom": "usdx" + }, + "collateral": { + "amount": "220764413", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1691", + "owner": "kava1mwxyxveamzwkxtnwkvcftlp4ulgexx4msuyvgr", + "principal": { + "amount": "19311084564", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "15567", + "denom": "usdx" + }, + "collateral": { + "amount": "159676", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:06:43.897016316Z", + "id": "1692", + "owner": "kava1zcamsjaf57tx3q79yl4e30knvl0gyckm0qpk7p", + "principal": { + "amount": "10015714", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "34057438", + "denom": "usdx" + }, + "collateral": { + "amount": "256799913", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1698", + "owner": "kava1f98urpz5jj0tfhm0dy6dguk8qp4fq8yr7g0fyq", + "principal": { + "amount": "19600000000", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "200635", + "denom": "usdx" + }, + "collateral": { + "amount": "199999998", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1703", + "owner": "kava1ygqcu6c6jsc443apwnad4ck0rrgpcv7hfqtsd8", + "principal": { + "amount": "22536239592", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "22867308", + "denom": "usdx" + }, + "collateral": { + "amount": "445273136", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1705", + "owner": "kava1yc7r3qfqxlds6aw6p9egy42vn8n8wu5hd0ksvm", + "principal": { + "amount": "31834197426", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "131875632", + "denom": "usdx" + }, + "collateral": { + "amount": "1300499676", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1709", + "owner": "kava1tstf3u4cw7u4xyu7wxdrnmrpvvmfamq3twcj7f", + "principal": { + "amount": "88727696855", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "64820171", + "denom": "usdx" + }, + "collateral": { + "amount": "499999933", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1710", + "owner": "kava165p5a7rjjzj4hjn80w3nwjr8e7kglm42xgy0w2", + "principal": { + "amount": "40000000000", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "1117830", + "denom": "usdx" + }, + "collateral": { + "amount": "20989666", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1714", + "owner": "kava1mj0qe9u9ztfzhnk4xzm0wu37g0m4npaa9lsjgx", + "principal": { + "amount": "1196291609", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "1906599", + "denom": "usdx" + }, + "collateral": { + "amount": "59999998", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1716", + "owner": "kava1qm6gheafpg68x5z24gmuknn4l6492q7gm0l9d7", + "principal": { + "amount": "1200000000", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "599449628", + "denom": "usdx" + }, + "collateral": { + "amount": "5001749700", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1723", + "owner": "kava10wyahu4d23fgtzjdxc998gn7z48lc2nte79z37", + "principal": { + "amount": "380000000000", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "4709660", + "denom": "usdx" + }, + "collateral": { + "amount": "40119956", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1725", + "owner": "kava1u205gp2kxm7kj2ta2yhtpazdyc97xgy8e3re7k", + "principal": { + "amount": "2900000000", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "621029383", + "denom": "usdx" + }, + "collateral": { + "amount": "10005083067", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1726", + "owner": "kava1x242qk6jf2rv23ruvk6fmxp97gg2y75a9r2caq", + "principal": { + "amount": "659860638715", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "179971", + "denom": "usdx" + }, + "collateral": { + "amount": "57184152", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1729", + "owner": "kava14luenugtsynt0zme2qtp0t6sn6gq6rm83q5kag", + "principal": { + "amount": "5154645111", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "62828", + "denom": "usdx" + }, + "collateral": { + "amount": "1236402", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1732", + "owner": "kava1p42hz5v9330x7hrx07xgl5g7tw55vgkm2mdk9p", + "principal": { + "amount": "130075280", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "649844", + "denom": "usdx" + }, + "collateral": { + "amount": "599999996", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1735", + "owner": "kava1fg7fcs0vupc5lyy67hatkq2nak995w3m6cvhzm", + "principal": { + "amount": "67597640428", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "3155931", + "denom": "usdx" + }, + "collateral": { + "amount": "70527822", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1736", + "owner": "kava1k33pgvv8fs875ht5erf4qvqpdrhtlckt2twd93", + "principal": { + "amount": "5116869886", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "560768", + "denom": "usdx" + }, + "collateral": { + "amount": "4209963", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1743", + "owner": "kava1s84pcv6q8gvq262c4245yf59mg9xsdxgpngyul", + "principal": { + "amount": "400000000", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "14865", + "denom": "usdx" + }, + "collateral": { + "amount": "159676", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:06:27.75505786Z", + "id": "1755", + "owner": "kava1myxznqgakl9va5cmg946yrh3tjhnjtx40e8p0a", + "principal": { + "amount": "11351573", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "436432", + "denom": "usdx" + }, + "collateral": { + "amount": "120762086", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1757", + "owner": "kava1d9j83ll3e0jh5w8kycjcmzcm2wdy0mr353gagc", + "principal": { + "amount": "11912753283", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "5601436", + "denom": "usdx" + }, + "collateral": { + "amount": "128143145", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1766", + "owner": "kava1y0rytym5j70wl9cdh39e4myclgdhsctvp8mh7e", + "principal": { + "amount": "9077450221", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "8417596", + "denom": "usdx" + }, + "collateral": { + "amount": "135635914", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1773", + "owner": "kava1wnpxrmcn8nu9skukt7fzwyr98f3x059kt35v3p", + "principal": { + "amount": "8268345572", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "7565", + "denom": "usdx" + }, + "collateral": { + "amount": "155264", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:06:50.815581672Z", + "id": "1774", + "owner": "kava1y3v4zynrf08tf2qhyv53039wcj77qagjw0w9g6", + "principal": { + "amount": "11809265", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "3342172", + "denom": "usdx" + }, + "collateral": { + "amount": "52096485", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1775", + "owner": "kava1caukx55c2qcgcy94ny4y97jag8nst6nwcat06j", + "principal": { + "amount": "4985192947", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "194260", + "denom": "usdx" + }, + "collateral": { + "amount": "5000000", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1779", + "owner": "kava1u746y26ykuuhurg2rzmzvpxvwvu34aw8q79ape", + "principal": { + "amount": "354626188", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "16610516", + "denom": "usdx" + }, + "collateral": { + "amount": "598999836", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1786", + "owner": "kava1e37mdk9efcj2udustjdaw8acx2chcwdluwvrvs", + "principal": { + "amount": "30010000000", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "273624", + "denom": "usdx" + }, + "collateral": { + "amount": "10848422", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1789", + "owner": "kava1mn72s3vjncj3gry8kwe795j4cr9rmtn90a0v5x", + "principal": { + "amount": "425000000", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "924557", + "denom": "usdx" + }, + "collateral": { + "amount": "32049747", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1790", + "owner": "kava13lmh7zyl4rtvvxyx9tszwfv4efsmfz7ahydl78", + "principal": { + "amount": "2028058524", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "97808234", + "denom": "usdx" + }, + "collateral": { + "amount": "999999838", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1792", + "owner": "kava15fu6ehw756hd3dyvws0xfwmrugfz8m6f5n030l", + "principal": { + "amount": "80000000000", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "4607706", + "denom": "usdx" + }, + "collateral": { + "amount": "112999678", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1793", + "owner": "kava1q7zew0fsez5k48elvj79dsu3k2w0k8ktej3un7", + "principal": { + "amount": "7963955459", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "7659938", + "denom": "usdx" + }, + "collateral": { + "amount": "164009342", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1799", + "owner": "kava1pu9g0q0ceduaq0827l0pkyjgejcfn66zg9n0rq", + "principal": { + "amount": "10748106213", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "327470", + "denom": "usdx" + }, + "collateral": { + "amount": "5626969", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1802", + "owner": "kava1hqwlepgc9z8taf3hmxsfg840st6r7ptazhljme", + "principal": { + "amount": "518268191", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "1245533", + "denom": "usdx" + }, + "collateral": { + "amount": "11999838", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1803", + "owner": "kava19mtegk4rd6fjfxjsmknn8862gcmfd32myj7sva", + "principal": { + "amount": "1100000000", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "6556755", + "denom": "usdx" + }, + "collateral": { + "amount": "144510928", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1804", + "owner": "kava1e2pmq54dyq8xzdq6n9dnquvt0ux3mu2n56wqgg", + "principal": { + "amount": "9299843900", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "961027", + "denom": "usdx" + }, + "collateral": { + "amount": "10486328", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1806", + "owner": "kava1vsk22xy2sgtflh8uratwwg2ju69twmdrfwzq4x", + "principal": { + "amount": "909514518", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "186829372", + "denom": "usdx" + }, + "collateral": { + "amount": "3690946381", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1809", + "owner": "kava123a8tsfuyzn285cmt600u6tpwxg7kmrgazj2hv", + "principal": { + "amount": "323065088571", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "28878387", + "denom": "usdx" + }, + "collateral": { + "amount": "531052697", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1820", + "owner": "kava1nr3a995c3ywl8d4cplczsavvtfd5qhetffypd2", + "principal": { + "amount": "30000000000", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "1421317", + "denom": "usdx" + }, + "collateral": { + "amount": "348971106", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1828", + "owner": "kava14m0dtdvs9pqeqg74g7jnxcr9tkpl4maa7r5mkv", + "principal": { + "amount": "38586834124", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "3594143", + "denom": "usdx" + }, + "collateral": { + "amount": "132743010", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1832", + "owner": "kava1fuwnpvv6heued9mmhlphpwgyu4fu0tzvcan9u9", + "principal": { + "amount": "9681671572", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "4042737", + "denom": "usdx" + }, + "collateral": { + "amount": "70000000", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1835", + "owner": "kava15adrjuvyk62x0klyukaums95frw5usm4v6daj9", + "principal": { + "amount": "4900000000", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "3313744", + "denom": "usdx" + }, + "collateral": { + "amount": "66037550", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1840", + "owner": "kava1x9mmnhc7rutx9jjqgv79sv7vr6xpqjymqepzlq", + "principal": { + "amount": "5674266547", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "1121340", + "denom": "usdx" + }, + "collateral": { + "amount": "49972802", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1847", + "owner": "kava1kk0uu0ax7ka0jle8k4shxf95ts3c7grv838jhl", + "principal": { + "amount": "5100461569", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "562205", + "denom": "usdx" + }, + "collateral": { + "amount": "10553295", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1853", + "owner": "kava1zrthvpd9rjmyapya6xxf2ywrs4h3ugfmfw4rzu", + "principal": { + "amount": "892162704", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "279", + "denom": "usdx" + }, + "collateral": { + "amount": "2078542", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:06:43.897016316Z", + "id": "1854", + "owner": "kava1e9h2eu9plxlfzdy6wfcg0477tjv7yvumutva6q", + "principal": { + "amount": "10051578", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "231080", + "denom": "usdx" + }, + "collateral": { + "amount": "7329143", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1861", + "owner": "kava1hy7prkth4zyghgm9vj5awqc7h4gn94gw9tq3rm", + "principal": { + "amount": "452130034", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "16441160", + "denom": "usdx" + }, + "collateral": { + "amount": "499499753", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1874", + "owner": "kava1t7v48gu6jh26av0e089sxq4n4jxwckp8v7hp6p", + "principal": { + "amount": "35000000000", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "2483985", + "denom": "usdx" + }, + "collateral": { + "amount": "80002113", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1875", + "owner": "kava1rle08y653c80s9rwmpuxq9nyq5lg9c47l2m4qs", + "principal": { + "amount": "5400000000", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "14547455", + "denom": "usdx" + }, + "collateral": { + "amount": "892533097", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1876", + "owner": "kava1ehtxa3cy5s5ulksfswx5c7umftlm0p2yrnc6vd", + "principal": { + "amount": "89500000379", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "507306", + "denom": "usdx" + }, + "collateral": { + "amount": "23790473", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1879", + "owner": "kava1wq7989t7sgn453ky9tznwtsy5m87hrt7gm8p34", + "principal": { + "amount": "1281298117", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "31031495", + "denom": "usdx" + }, + "collateral": { + "amount": "910212001", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1887", + "owner": "kava15w26ypf03ew40s2rlpvz6w6zewjllux2nd9zh6", + "principal": { + "amount": "94300000000", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "1797517", + "denom": "usdx" + }, + "collateral": { + "amount": "109999996", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1892", + "owner": "kava1z6c9537t52clapvjzhl0r06urn9y5ptl3rdn5y", + "principal": { + "amount": "6400000000", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "2854149", + "denom": "usdx" + }, + "collateral": { + "amount": "126523785", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1894", + "owner": "kava1r6863cfuphfqn9e8csrh5nwt478hqys0m55jev", + "principal": { + "amount": "10320806815", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "105841", + "denom": "usdx" + }, + "collateral": { + "amount": "5369633", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1900", + "owner": "kava1k8ermdwe2456hxypxdtdjhtakucwph8zjsqvaj", + "principal": { + "amount": "500000000", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "3743", + "denom": "usdx" + }, + "collateral": { + "amount": "499998", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1905", + "owner": "kava1xcku3nqxm5jt7fhgrk9pvpdqqfjkxlwx2m8aka", + "principal": { + "amount": "31000000", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "20146", + "denom": "usdx" + }, + "collateral": { + "amount": "1985120", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1906", + "owner": "kava10fu8zc5qtw2wa50z244cnlxxa3pjs8el0hc8p0", + "principal": { + "amount": "196330293", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "1048", + "denom": "usdx" + }, + "collateral": { + "amount": "226095", + "denom": "btcb" + }, + "fees_updated": "2020-12-01T19:06:43.897016316Z", + "id": "1908", + "owner": "kava1jcr60d69sjymnkvdfn9vc4flxukn4gy9cd5rq9", + "principal": { + "amount": "10000368", + "denom": "usdx" + }, + "type": "btcb-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "1299980000", + "denom": "busd" + }, + "fees_updated": "2020-11-05T19:03:43.914871651Z", + "id": "1369", + "owner": "kava1yde8s4pa2gqqe4mz4l4aky3nxjje0r887uaauw", + "principal": { + "amount": "12000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "1999980000", + "denom": "busd" + }, + "fees_updated": "2020-11-05T19:50:37.811001967Z", + "id": "1373", + "owner": "kava1vlpsrmdyuywvaqrv7rx6xga224sqfwz3fyfhwq", + "principal": { + "amount": "15000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "15989637519000", + "denom": "busd" + }, + "fees_updated": "2020-11-05T21:07:16.067100695Z", + "id": "1379", + "owner": "kava1rea6zxqq78klh7uhf78juqp9nmtl53j7hsnquk", + "principal": { + "amount": "157500000044", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "200220099134", + "denom": "busd" + }, + "fees_updated": "2020-11-06T02:59:30.382197492Z", + "id": "1386", + "owner": "kava1zuslhtgj5r8n95k833w5lttnjzuxcpjy7ql3c5", + "principal": { + "amount": "1695313345", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "18000000000", + "denom": "busd" + }, + "fees_updated": "2020-11-06T03:06:35.263242647Z", + "id": "1387", + "owner": "kava13d3nklvf22whykz5a8vt8qlj66029gpwqcmj69", + "principal": { + "amount": "169000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "132148250000", + "denom": "busd" + }, + "fees_updated": "2020-11-06T08:20:02.269422526Z", + "id": "1398", + "owner": "kava1a7vqpgveaa97vvgh8rx2apycrjjjq4dw33hp6p", + "principal": { + "amount": "660545742", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "12100000000", + "denom": "busd" + }, + "fees_updated": "2020-11-07T06:39:44.410849117Z", + "id": "1428", + "owner": "kava1mz2vfw29fzkg4yj9wfh99nkgx46unhrxtyxqhc", + "principal": { + "amount": "100000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "750057040000", + "denom": "busd" + }, + "fees_updated": "2020-11-07T06:56:15.282604079Z", + "id": "1430", + "owner": "kava10lhnlwlek6yg5n734jn8qukur2kjjhcw09xagl", + "principal": { + "amount": "6700000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "14393428255", + "denom": "busd" + }, + "fees_updated": "2020-11-09T04:09:40.4622144Z", + "id": "1448", + "owner": "kava1hlp63v8s9dmsfjumcw7sesa7gqjcj2vff7tvkq", + "principal": { + "amount": "135383731", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "3507505656909", + "denom": "busd" + }, + "fees_updated": "2020-11-09T09:34:05.834112388Z", + "id": "1455", + "owner": "kava17p6klf9l6m326ewrax8qyje78ztr6pc8auqjhj", + "principal": { + "amount": "29778076618", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "900472940000", + "denom": "busd" + }, + "fees_updated": "2020-11-09T09:41:57.267240063Z", + "id": "1456", + "owner": "kava1zdtnnt6e6n949h39eskp3m3jnmzsrrda9wfl7a", + "principal": { + "amount": "8860363564", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "5000000000", + "denom": "busd" + }, + "fees_updated": "2020-11-09T13:42:51.690011442Z", + "id": "1458", + "owner": "kava1fg7fcs0vupc5lyy67hatkq2nak995w3m6cvhzm", + "principal": { + "amount": "41000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "5500000000", + "denom": "busd" + }, + "fees_updated": "2020-11-09T15:00:15.321393292Z", + "id": "1459", + "owner": "kava1q9dmpl7y839hyvhg3w57spwfvlxls9vf9xe27h", + "principal": { + "amount": "54000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "100416367936925", + "denom": "busd" + }, + "fees_updated": "2020-11-09T18:37:46.243880046Z", + "id": "1467", + "owner": "kava1ahpp070dzd2fctueeufddql8eh9sx2sy54axxa", + "principal": { + "amount": "992220000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "4248159036400", + "denom": "busd" + }, + "fees_updated": "2020-11-09T18:39:01.149871286Z", + "id": "1468", + "owner": "kava1mazzh08dgdqrn8y6khq7snr9jgun3vtlzdhq7c", + "principal": { + "amount": "39957931531", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "49715530000", + "denom": "busd" + }, + "fees_updated": "2020-11-09T20:55:26.80890155Z", + "id": "1471", + "owner": "kava1c5lzj543l3xlz8s4s03phkkm4p0g6qg570vjys", + "principal": { + "amount": "180783745", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "4246250860498", + "denom": "busd" + }, + "fees_updated": "2020-11-09T21:39:18.694532038Z", + "id": "1472", + "owner": "kava1hfmlqt5qxatfzh3jnyx55ztl050ev7u6l9qefq", + "principal": { + "amount": "41400000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "514363386789", + "denom": "busd" + }, + "fees_updated": "2020-11-09T23:18:45.247542746Z", + "id": "1474", + "owner": "kava1n8hvr4pnjfr5llkqtgpp8vt82j5jzn080t0v7d", + "principal": { + "amount": "4950000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "85925015836", + "denom": "busd" + }, + "fees_updated": "2020-11-09T23:30:48.780590159Z", + "id": "1475", + "owner": "kava1hy7prkth4zyghgm9vj5awqc7h4gn94gw9tq3rm", + "principal": { + "amount": "758000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "18694916116722", + "denom": "busd" + }, + "fees_updated": "2020-11-10T03:15:20.58919399Z", + "id": "1483", + "owner": "kava1q3a9nggfp94wv6yntjt3xq9wc6gfnnkrwp2my8", + "principal": { + "amount": "182320000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "296648657419999", + "denom": "busd" + }, + "fees_updated": "2020-11-10T03:16:57.083787985Z", + "id": "1484", + "owner": "kava1p79w5f6mallu3pqnqk6qh03xlxcmlp8hpew746", + "principal": { + "amount": "2871719000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "49999999860000", + "denom": "busd" + }, + "fees_updated": "2020-11-10T03:44:09.961749705Z", + "id": "1485", + "owner": "kava1uqm720kpl45qhvkttz5ul46qzgch7ltg0wc32j", + "principal": { + "amount": "495000000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "1181113429092", + "denom": "busd" + }, + "fees_updated": "2020-11-10T06:58:06.708273193Z", + "id": "1495", + "owner": "kava1y56rm72h5nm6psg2k7mxx2gjtldyme2wyt2nds", + "principal": { + "amount": "10280000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "502819379035", + "denom": "busd" + }, + "fees_updated": "2020-11-10T07:25:58.186927031Z", + "id": "1499", + "owner": "kava1mwxyxveamzwkxtnwkvcftlp4ulgexx4msuyvgr", + "principal": { + "amount": "4700000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "3259818924929", + "denom": "busd" + }, + "fees_updated": "2020-11-10T07:35:02.760134908Z", + "id": "1501", + "owner": "kava1yw6l03x2ezr7mkpalntlj6kxxq6q049l078k69", + "principal": { + "amount": "31779000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "5922687702623", + "denom": "busd" + }, + "fees_updated": "2020-11-10T08:27:42.829813151Z", + "id": "1505", + "owner": "kava1gr8e5w5n804gn3ypvvgdqx6535d6ukmmxcqps7", + "principal": { + "amount": "55000000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "85279066892", + "denom": "busd" + }, + "fees_updated": "2020-11-10T09:25:47.311849469Z", + "id": "1508", + "owner": "kava1drk0qa554p4r9t4vw20sqn84m9xz7dp2gr0kfy", + "principal": { + "amount": "802129837", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "484220882900", + "denom": "busd" + }, + "fees_updated": "2020-11-10T10:18:26.974313292Z", + "id": "1511", + "owner": "kava182mzj3c7hg96fsaratn0wt2khgtgxgvlwhg77e", + "principal": { + "amount": "4500000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "145175922300", + "denom": "busd" + }, + "fees_updated": "2020-11-10T10:27:11.740575747Z", + "id": "1512", + "owner": "kava1z0u0efzn8llallan08kenpuj262etz9392phf4", + "principal": { + "amount": "1100000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "25215725923000", + "denom": "busd" + }, + "fees_updated": "2020-11-10T13:12:58.009025596Z", + "id": "1514", + "owner": "kava1lrrzm6celm0hp9nkm27etlyq0tp74szn2wdfg8", + "principal": { + "amount": "170013000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "1088223380000", + "denom": "busd" + }, + "fees_updated": "2020-11-10T14:26:06.071821207Z", + "id": "1517", + "owner": "kava1rdz99mwratcl90td2t4pwvce6k3v4elyyymvx5", + "principal": { + "amount": "8957175927", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "19999999660000", + "denom": "busd" + }, + "fees_updated": "2020-11-10T15:55:10.299131521Z", + "id": "1519", + "owner": "kava1nt2vxll5s7zcs7g77t8a5fl5039xnjr73z40u4", + "principal": { + "amount": "167600000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "32100000000", + "denom": "busd" + }, + "fees_updated": "2020-11-10T16:03:16.930521157Z", + "id": "1521", + "owner": "kava1en7rx4gygys7ah237vt2tq8wwph40mx9ulwu0s", + "principal": { + "amount": "245000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "260226427000", + "denom": "busd" + }, + "fees_updated": "2020-11-10T16:08:01.406109124Z", + "id": "1522", + "owner": "kava1qmzley89aj4kr9l6qww75nca9zxfw8wufssuuf", + "principal": { + "amount": "2270792047", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "9999980000", + "denom": "busd" + }, + "fees_updated": "2020-11-10T16:36:03.547276042Z", + "id": "1523", + "owner": "kava16hgzsqyuyf3zd3atewlz7h03pgs836x5qghxz4", + "principal": { + "amount": "75000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "120657371620", + "denom": "busd" + }, + "fees_updated": "2020-11-11T10:52:24.43015817Z", + "id": "1543", + "owner": "kava1dv0zgqn33sjyyx7jhxt3s9c2ug239t8fnph42q", + "principal": { + "amount": "1100000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "2071307385674", + "denom": "busd" + }, + "fees_updated": "2020-11-11T12:24:05.041912007Z", + "id": "1545", + "owner": "kava176nfnxq2325z72jmxragelpx2jx3fme4g796pd", + "principal": { + "amount": "18099000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "6854775240", + "denom": "busd" + }, + "fees_updated": "2020-11-11T16:07:01.470885976Z", + "id": "1549", + "owner": "kava1e7eaayk208yn8grtr7aw7xg376h4qpums7fgg8", + "principal": { + "amount": "31000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "3465778250682", + "denom": "busd" + }, + "fees_updated": "2020-11-12T14:00:52.48196292Z", + "id": "1565", + "owner": "kava1wjjg0mvsfgnskjj7qq28uaxqwq5h38q6nh5ah8", + "principal": { + "amount": "30489897763", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "7012770418578", + "denom": "busd" + }, + "fees_updated": "2020-11-13T15:09:07.400532908Z", + "id": "1574", + "owner": "kava1f98urpz5jj0tfhm0dy6dguk8qp4fq8yr7g0fyq", + "principal": { + "amount": "64549989821", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "33895546575", + "denom": "busd" + }, + "fees_updated": "2020-11-13T19:29:12.715951493Z", + "id": "1577", + "owner": "kava1t2u6mhqng5tkwkvjkj8fcp7szq2lkaffydwh2j", + "principal": { + "amount": "289376098", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "73800160000", + "denom": "busd" + }, + "fees_updated": "2020-11-17T03:38:19.620416135Z", + "id": "1603", + "owner": "kava1xwkrx4ytz6vsa5d3pc0pcsyr6twuwfdwap2vvy", + "principal": { + "amount": "700000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "5846565792", + "denom": "busd" + }, + "fees_updated": "2020-11-17T03:58:39.026902585Z", + "id": "1615", + "owner": "kava1nxg24gzzh9k8pl06frvp7989g3kk4ualgqkylx", + "principal": { + "amount": "57000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "9994160000", + "denom": "busd" + }, + "fees_updated": "2020-11-17T06:18:28.432117544Z", + "id": "1630", + "owner": "kava1a7vmnk0qfwuxq0jsek3hr798xutu24ga78s3ys", + "principal": { + "amount": "90000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "291977292852", + "denom": "busd" + }, + "fees_updated": "2020-11-17T10:43:06.006201313Z", + "id": "1649", + "owner": "kava15ys7x9ra820jyrwztqaps9g0dawcacvcxlap5n", + "principal": { + "amount": "2800000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "15999988680000", + "denom": "busd" + }, + "fees_updated": "2020-11-17T13:04:57.189358346Z", + "id": "1659", + "owner": "kava1snaq99cvtjzcu9uagtw5j7guu62gpr75q0cvh5", + "principal": { + "amount": "150000000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "150797182273", + "denom": "busd" + }, + "fees_updated": "2020-11-17T14:56:28.137412238Z", + "id": "1664", + "owner": "kava1qtp927u54rxnn8d7yfkr9dsf9xguzzy40vyyvw", + "principal": { + "amount": "1400000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "296230360000", + "denom": "busd" + }, + "fees_updated": "2020-11-17T15:01:07.229729697Z", + "id": "1665", + "owner": "kava1fymnm880d4m03276vwwlm4xwtsswyqq07jg53s", + "principal": { + "amount": "2800000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "37025109900", + "denom": "busd" + }, + "fees_updated": "2020-11-17T15:19:45.902081218Z", + "id": "1667", + "owner": "kava12ghgptqj954d7gr4uh0z5qesxaz3nffhkcam6r", + "principal": { + "amount": "346000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "30270695603", + "denom": "busd" + }, + "fees_updated": "2020-11-18T02:48:47.880650942Z", + "id": "1688", + "owner": "kava1m2unjdkmyvn8720y3guynt6q2ve59furp5cqu5", + "principal": { + "amount": "256344263", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "44415960000", + "denom": "busd" + }, + "fees_updated": "2020-11-18T09:56:43.084532528Z", + "id": "1693", + "owner": "kava1tzd292t6ykl5s4aj0qv2sp206py94z8md33aps", + "principal": { + "amount": "161512582", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "2257795140000", + "denom": "busd" + }, + "fees_updated": "2020-11-18T10:27:41.731576442Z", + "id": "1694", + "owner": "kava1kfrjwuur93wthdwc6kpf36lwftdzz22wxe5gae", + "principal": { + "amount": "21340000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "1345394580000", + "denom": "busd" + }, + "fees_updated": "2020-11-18T11:08:35.535080069Z", + "id": "1695", + "owner": "kava149vcm760asu4uty5qlxsmkz2hh8duw2t7us7hw", + "principal": { + "amount": "4892343927", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "284865516543", + "denom": "busd" + }, + "fees_updated": "2020-11-18T15:46:58.761224165Z", + "id": "1699", + "owner": "kava1famggza0sju5964gls45pmz2662fluwst53xq3", + "principal": { + "amount": "2500000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "9997080000", + "denom": "busd" + }, + "fees_updated": "2020-11-18T16:25:50.86928357Z", + "id": "1700", + "owner": "kava1mu69p2n7ejceg504q370q2v4aulhjfudeg00tm", + "principal": { + "amount": "94031940", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "988619367459", + "denom": "busd" + }, + "fees_updated": "2020-11-18T17:10:23.65482076Z", + "id": "1701", + "owner": "kava1r0909tza7argym6587z0mnmsn6c532ew5qd06w", + "principal": { + "amount": "9641000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "11375319476621", + "denom": "busd" + }, + "fees_updated": "2020-11-18T18:22:34.87900395Z", + "id": "1706", + "owner": "kava1as5f599ltjc9uy5dpne9pkhzuylcdhsj7sa2du", + "principal": { + "amount": "100141688865", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "3016813596035", + "denom": "busd" + }, + "fees_updated": "2020-11-18T19:39:04.038667908Z", + "id": "1708", + "owner": "kava1jkxnprst3cty3jm0evz4cr077972v05y39uf9j", + "principal": { + "amount": "29487000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "42536838483", + "denom": "busd" + }, + "fees_updated": "2020-11-18T21:28:50.969253374Z", + "id": "1712", + "owner": "kava1p42hz5v9330x7hrx07xgl5g7tw55vgkm2mdk9p", + "principal": { + "amount": "400000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "155975327230", + "denom": "busd" + }, + "fees_updated": "2020-11-19T20:46:55.649633578Z", + "id": "1734", + "owner": "kava127lary0erprnrv9vn3wykyt9pjm5a5tdwdnm3h", + "principal": { + "amount": "1450000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "4372659059600", + "denom": "busd" + }, + "fees_updated": "2020-11-20T03:48:01.014390321Z", + "id": "1739", + "owner": "kava18d0er3p3esg4t0xq8nlsd568p2xh5l2rw864k0", + "principal": { + "amount": "42400000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "8496884226821", + "denom": "busd" + }, + "fees_updated": "2020-11-20T08:51:21.397439091Z", + "id": "1747", + "owner": "kava1ctjlscze3lkppywq7mxsrytqp2ushf7vlsmjwg", + "principal": { + "amount": "79921188272", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "6500000000000", + "denom": "busd" + }, + "fees_updated": "2020-11-20T09:19:23.988326063Z", + "id": "1748", + "owner": "kava1zx2gfs37vszrgrxke22mtlfj6hpl72y03ur7xr", + "principal": { + "amount": "64000000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "329699856760000", + "denom": "busd" + }, + "fees_updated": "2020-11-20T19:32:40.620756859Z", + "id": "1752", + "owner": "kava15wyjwhj6zh79m7adm69pwl3nsq9z8gs9ezs4k7", + "principal": { + "amount": "3190806000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "10877081887214", + "denom": "busd" + }, + "fees_updated": "2020-11-21T03:05:27.527957233Z", + "id": "1758", + "owner": "kava1eu0s5hs52f4z8ld0hw3kuuwn07cgzauyda55n9", + "principal": { + "amount": "39553025044", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "17950000716216", + "denom": "busd" + }, + "fees_updated": "2020-11-21T14:35:15.183991399Z", + "id": "1768", + "owner": "kava1ehtxa3cy5s5ulksfswx5c7umftlm0p2yrnc6vd", + "principal": { + "amount": "177500000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "1043400000", + "denom": "busd" + }, + "fees_updated": "2020-11-22T09:37:08.062670203Z", + "id": "1785", + "owner": "kava19ljxvpg05r9nd03965dvh9pp22s6t7sc8zs04y", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "12500000000", + "denom": "busd" + }, + "fees_updated": "2020-11-22T11:21:35.161068943Z", + "id": "1788", + "owner": "kava1qldlnzhnjv9zeagx6a9yrqxpqrcujh8ln998mn", + "principal": { + "amount": "47000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "16456802943", + "denom": "busd" + }, + "fees_updated": "2020-11-22T15:59:39.543236656Z", + "id": "1794", + "owner": "kava1xu4ft9ul3jh9khrjt69rhmt6pfd3jtea0wstv8", + "principal": { + "amount": "40000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "30000000000", + "denom": "busd" + }, + "fees_updated": "2020-11-23T20:06:49.125954365Z", + "id": "1811", + "owner": "kava1zszzt0tlu9ry66yk7krtl8z4xn85c0ql7j64j3", + "principal": { + "amount": "250000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "289119099333", + "denom": "busd" + }, + "fees_updated": "2020-11-23T20:38:07.428866265Z", + "id": "1812", + "owner": "kava10fu8zc5qtw2wa50z244cnlxxa3pjs8el0hc8p0", + "principal": { + "amount": "2719437072", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "1149909240000", + "denom": "busd" + }, + "fees_updated": "2020-11-24T02:43:31.259847369Z", + "id": "1814", + "owner": "kava1zrthvpd9rjmyapya6xxf2ywrs4h3ugfmfw4rzu", + "principal": { + "amount": "11168170836", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "4800000000", + "denom": "busd" + }, + "fees_updated": "2020-11-24T12:46:09.899750998Z", + "id": "1819", + "owner": "kava1t7v48gu6jh26av0e089sxq4n4jxwckp8v7hp6p", + "principal": { + "amount": "17818109", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "5999999980000", + "denom": "busd" + }, + "fees_updated": "2020-11-24T14:11:30.51318377Z", + "id": "1821", + "owner": "kava1nr3a995c3ywl8d4cplczsavvtfd5qhetffypd2", + "principal": { + "amount": "57900000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "1099999980000", + "denom": "busd" + }, + "fees_updated": "2020-11-24T14:19:53.548255992Z", + "id": "1822", + "owner": "kava15jtcnhucatrg8z70s5huxpyhnwf2klupv6xqyq", + "principal": { + "amount": "9000000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "202729450101", + "denom": "busd" + }, + "fees_updated": "2020-11-25T12:57:43.881125728Z", + "id": "1831", + "owner": "kava1caukx55c2qcgcy94ny4y97jag8nst6nwcat06j", + "principal": { + "amount": "1997000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "1000000000000", + "denom": "busd" + }, + "fees_updated": "2020-11-25T14:22:00.421146804Z", + "id": "1836", + "owner": "kava1c2hulueujetjcpgwlnu07t47yg77rq3fxrqk0f", + "principal": { + "amount": "7900000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "1099864867155", + "denom": "busd" + }, + "fees_updated": "2020-11-25T15:00:03.497371134Z", + "id": "1837", + "owner": "kava15adrjuvyk62x0klyukaums95frw5usm4v6daj9", + "principal": { + "amount": "9000000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "29990000000000", + "denom": "busd" + }, + "fees_updated": "2020-11-25T22:02:22.360249908Z", + "id": "1841", + "owner": "kava1tstf3u4cw7u4xyu7wxdrnmrpvvmfamq3twcj7f", + "principal": { + "amount": "258000000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "259852315955", + "denom": "busd" + }, + "fees_updated": "2020-11-26T08:01:19.270036219Z", + "id": "1844", + "owner": "kava1wkn6z4xjrl2esflpdvxemn0m8hkv34ygh6xeaf", + "principal": { + "amount": "2000000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "500094180000", + "denom": "busd" + }, + "fees_updated": "2020-11-26T09:07:37.120283584Z", + "id": "1845", + "owner": "kava1tnf0zwaqx76lkpaj0un36kvwhver8dmynvr6zs", + "principal": { + "amount": "4400000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "25459258855138", + "denom": "busd" + }, + "fees_updated": "2020-11-26T12:24:28.731124821Z", + "id": "1846", + "owner": "kava19mtegk4rd6fjfxjsmknn8862gcmfd32myj7sva", + "principal": { + "amount": "248260000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "199794180000", + "denom": "busd" + }, + "fees_updated": "2020-11-27T03:40:10.914352878Z", + "id": "1855", + "owner": "kava1a97dqz7ptwv2pxrgcrp8a2e6vap6utj83av20k", + "principal": { + "amount": "1531000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "228306404000", + "denom": "busd" + }, + "fees_updated": "2020-11-27T05:12:06.073537398Z", + "id": "1856", + "owner": "kava10rmx7epkes54py97gjpn5qwr3xgjaln2f3yadl", + "principal": { + "amount": "2258000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "118637080000", + "denom": "busd" + }, + "fees_updated": "2020-11-27T10:37:10.506316756Z", + "id": "1859", + "owner": "kava18zpjg8wc9mmgkvsl5sg3esk7yrns6gsy4rs3ra", + "principal": { + "amount": "1000000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "1400000000", + "denom": "busd" + }, + "fees_updated": "2020-11-28T03:31:25.364186195Z", + "id": "1868", + "owner": "kava1dz5zhsa0uxw62y06mwmaazgkhgq49e7sun6nf3", + "principal": { + "amount": "12500000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "1400000000", + "denom": "busd" + }, + "fees_updated": "2020-11-28T03:37:38.313642364Z", + "id": "1869", + "owner": "kava1ha8cwpay5l293clga0sy0ersm8tqmv0gfgaejc", + "principal": { + "amount": "12500000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "65000000000", + "denom": "busd" + }, + "fees_updated": "2020-11-28T03:41:57.47322078Z", + "id": "1870", + "owner": "kava1chk4a3v96nhc5msc5f84f66ulujz7xdz9fh367", + "principal": { + "amount": "236363636", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "12361661289391", + "denom": "busd" + }, + "fees_updated": "2020-11-28T04:54:09.962492559Z", + "id": "1873", + "owner": "kava1tc5mkjya8upt82f3puaqdgahec520pw8zc2vd2", + "principal": { + "amount": "115000000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "12862026100", + "denom": "busd" + }, + "fees_updated": "2020-11-28T13:20:34.390159801Z", + "id": "1877", + "owner": "kava1dfymyx0q5jzq363whtcerdlug3jeyujwayn4vn", + "principal": { + "amount": "110000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "7358475000", + "denom": "busd" + }, + "fees_updated": "2020-11-29T09:13:22.971810806Z", + "id": "1888", + "owner": "kava1tzzdns8zkl0qptywnpr27eh0evj9zu45pc8f0g", + "principal": { + "amount": "40000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "10483560000", + "denom": "busd" + }, + "fees_updated": "2020-11-29T10:36:26.926865282Z", + "id": "1889", + "owner": "kava1pmaltcu0x97x8j5klc8xluaapkzcvztcvvvcnw", + "principal": { + "amount": "80000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "799994160000", + "denom": "busd" + }, + "fees_updated": "2020-11-29T12:30:01.688623881Z", + "id": "1890", + "owner": "kava1r6863cfuphfqn9e8csrh5nwt478hqys0m55jev", + "principal": { + "amount": "7800000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "100602380000", + "denom": "busd" + }, + "fees_updated": "2020-11-29T17:11:08.577208016Z", + "id": "1893", + "owner": "kava10l6gr3u8xqfd8jps724n4hkhd92fh9rugyx2n7", + "principal": { + "amount": "945000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "9999980000", + "denom": "busd" + }, + "fees_updated": "2020-11-30T00:44:42.688030489Z", + "id": "1898", + "owner": "kava1r52nyu8agn30xrm5yfu2npsthcqle9yck3fhtf", + "principal": { + "amount": "80000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "755499980000", + "denom": "busd" + }, + "fees_updated": "2020-11-30T10:15:15.593615824Z", + "id": "1902", + "owner": "kava1vg6q5k7q6s89lk852dgle8c5fr3rmrrr3jsvhy", + "principal": { + "amount": "6500000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "1096537081867", + "denom": "busd" + }, + "fees_updated": "2020-11-30T14:08:33.951852704Z", + "id": "1903", + "owner": "kava1ev5lnr4h8fhljgdtfe9gwlff4vg9ea6j8uxu3a", + "principal": { + "amount": "10000000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "5960458109170", + "denom": "busd" + }, + "fees_updated": "2020-11-30T15:46:38.405639897Z", + "id": "1904", + "owner": "kava15w26ypf03ew40s2rlpvz6w6zewjllux2nd9zh6", + "principal": { + "amount": "55000000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "60000046735124", + "denom": "busd" + }, + "fees_updated": "2020-11-30T20:56:08.024879706Z", + "id": "1907", + "owner": "kava10wyahu4d23fgtzjdxc998gn7z48lc2nte79z37", + "principal": { + "amount": "580000000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "2620118448775", + "denom": "busd" + }, + "fees_updated": "2020-12-01T05:11:27.596899867Z", + "id": "1909", + "owner": "kava1dn23hf3h0ysfh8j6t7f6vp95unvfet7qlgrkv4", + "principal": { + "amount": "22000000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "60023680000", + "denom": "busd" + }, + "fees_updated": "2020-12-01T05:56:24.09395087Z", + "id": "1912", + "owner": "kava19skxg5ce7j3l2nthpc0xcjuxj2sykjyht0dfs7", + "principal": { + "amount": "500000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "813548595054", + "denom": "busd" + }, + "fees_updated": "2020-12-01T09:31:19.023257902Z", + "id": "1913", + "owner": "kava1dpcgtp7hjvspg7nxpj7c7j25lnyyrau0g72jkd", + "principal": { + "amount": "6400000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "25000000000", + "denom": "busd" + }, + "fees_updated": "2020-12-01T12:36:47.960292352Z", + "id": "1914", + "owner": "kava1xcku3nqxm5jt7fhgrk9pvpdqqfjkxlwx2m8aka", + "principal": { + "amount": "180000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "6700000000", + "denom": "busd" + }, + "fees_updated": "2020-12-01T12:56:18.507915866Z", + "id": "1915", + "owner": "kava1zu4g7frl94szncff5marn63lurrk8rggterfvc", + "principal": { + "amount": "63000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "0", + "denom": "usdx" + }, + "collateral": { + "amount": "39816021000", + "denom": "busd" + }, + "fees_updated": "2020-12-01T17:48:04.627365149Z", + "id": "1919", + "owner": "kava13za9r4nk42aqkt8fw79wzf9r56gjatpc58ahvy", + "principal": { + "amount": "355000000", + "denom": "usdx" + }, + "type": "busd-a" + }, + { + "accumulated_fees": { + "amount": "138667", + "denom": "usdx" + }, + "collateral": { + "amount": "3006990000", + "denom": "busd" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1534", + "owner": "kava1ed0esw7jp8w580r052rhna5q8elw26y9a2td60", + "principal": { + "amount": "10934516", + "denom": "usdx" + }, + "type": "busd-b" + }, + { + "accumulated_fees": { + "amount": "2211639", + "denom": "usdx" + }, + "collateral": { + "amount": "18900000000", + "denom": "busd" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1539", + "owner": "kava1kldesu66y2telgvupaknyzx8ague6kk5kz052e", + "principal": { + "amount": "100000000", + "denom": "usdx" + }, + "type": "busd-b" + }, + { + "accumulated_fees": { + "amount": "125845", + "denom": "usdx" + }, + "collateral": { + "amount": "1199960000", + "denom": "busd" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1592", + "owner": "kava1ns8hmay6uh3p4j8ydr0hrvh0nxq9yu260xqchw", + "principal": { + "amount": "10000000", + "denom": "usdx" + }, + "type": "busd-b" + }, + { + "accumulated_fees": { + "amount": "4419410", + "denom": "usdx" + }, + "collateral": { + "amount": "78007141034", + "denom": "busd" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1839", + "owner": "kava1w05lzr3tj72n33vam3v0qddq05hf605a6k92u5", + "principal": { + "amount": "655000000", + "denom": "usdx" + }, + "type": "busd-b" + }, + { + "accumulated_fees": { + "amount": "42081", + "denom": "usdx" + }, + "collateral": { + "amount": "1314442237", + "denom": "busd" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1862", + "owner": "kava1gl9904w9u3znw9hy7eh7durrqnwdq44rastfyt", + "principal": { + "amount": "11352001", + "denom": "usdx" + }, + "type": "busd-b" + }, + { + "accumulated_fees": { + "amount": "66333", + "denom": "usdx" + }, + "collateral": { + "amount": "25000000000", + "denom": "xrpb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1375", + "owner": "kava1vlpsrmdyuywvaqrv7rx6xga224sqfwz3fyfhwq", + "principal": { + "amount": "22248636", + "denom": "usdx" + }, + "type": "xrpb-a" + }, + { + "accumulated_fees": { + "amount": "2986106", + "denom": "usdx" + }, + "collateral": { + "amount": "1004962800000", + "denom": "xrpb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1381", + "owner": "kava1zuslhtgj5r8n95k833w5lttnjzuxcpjy7ql3c5", + "principal": { + "amount": "914079781", + "denom": "usdx" + }, + "type": "xrpb-a" + }, + { + "accumulated_fees": { + "amount": "15737", + "denom": "usdx" + }, + "collateral": { + "amount": "8520808428", + "denom": "xrpb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1382", + "owner": "kava1sz6sm2arpa0cgufngdl04yxn4t2kyhepaf4klk", + "principal": { + "amount": "10538604", + "denom": "usdx" + }, + "type": "xrpb-a" + }, + { + "accumulated_fees": { + "amount": "25182", + "denom": "usdx" + }, + "collateral": { + "amount": "10312687900", + "denom": "xrpb" + }, + "fees_updated": "2020-12-01T19:07:10.536407474Z", + "id": "1402", + "owner": "kava1lynr3f7zqhpcwacvatewcwj0ar5q9sgx7tesj4", + "principal": { + "amount": "22529000", + "denom": "usdx" + }, + "type": "xrpb-a" + }, + { + "accumulated_fees": { + "amount": "1039610", + "denom": "usdx" + }, + "collateral": { + "amount": "199334393490", + "denom": "xrpb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1435", + "owner": "kava1sxhs7nrnmz5ypxjjx809wk92wy3uwz0x456r8w", + "principal": { + "amount": "556332471", + "denom": "usdx" + }, + "type": "xrpb-a" + }, + { + "accumulated_fees": { + "amount": "30397", + "denom": "usdx" + }, + "collateral": { + "amount": "24527390000", + "denom": "xrpb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1436", + "owner": "kava1hlp63v8s9dmsfjumcw7sesa7gqjcj2vff7tvkq", + "principal": { + "amount": "72912215", + "denom": "usdx" + }, + "type": "xrpb-a" + }, + { + "accumulated_fees": { + "amount": "1134266", + "denom": "usdx" + }, + "collateral": { + "amount": "299977800000", + "denom": "xrpb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1437", + "owner": "kava1n5eml55pqa3nm74rw589l3uqzmafytcz4e37zv", + "principal": { + "amount": "474649610", + "denom": "usdx" + }, + "type": "xrpb-a" + }, + { + "accumulated_fees": { + "amount": "16462", + "denom": "usdx" + }, + "collateral": { + "amount": "8131036400", + "denom": "xrpb" + }, + "fees_updated": "2020-12-01T19:06:43.897016316Z", + "id": "1469", + "owner": "kava15neu5ermme78khn448pwqqdthy4zl2pxaec780", + "principal": { + "amount": "10683905", + "denom": "usdx" + }, + "type": "xrpb-a" + }, + { + "accumulated_fees": { + "amount": "16477", + "denom": "usdx" + }, + "collateral": { + "amount": "9480972600", + "denom": "xrpb" + }, + "fees_updated": "2020-12-01T19:06:43.897016316Z", + "id": "1470", + "owner": "kava1cq0pd4w270sl65fvp4w067exxhhnvagfxcvn36", + "principal": { + "amount": "10647790", + "denom": "usdx" + }, + "type": "xrpb-a" + }, + { + "accumulated_fees": { + "amount": "1074798", + "denom": "usdx" + }, + "collateral": { + "amount": "500017800000", + "denom": "xrpb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1516", + "owner": "kava1nzq60hrphyr8anvkw6fv93mhafew7ez4tq9ahv", + "principal": { + "amount": "425504036", + "denom": "usdx" + }, + "type": "xrpb-a" + }, + { + "accumulated_fees": { + "amount": "18102", + "denom": "usdx" + }, + "collateral": { + "amount": "8065491200", + "denom": "xrpb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1531", + "owner": "kava10l6gr3u8xqfd8jps724n4hkhd92fh9rugyx2n7", + "principal": { + "amount": "11618210", + "denom": "usdx" + }, + "type": "xrpb-a" + }, + { + "accumulated_fees": { + "amount": "3314883", + "denom": "usdx" + }, + "collateral": { + "amount": "1015099900000", + "denom": "xrpb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1579", + "owner": "kava18utzytkj0unzevcm4jzxncu95prc8x5wqcnt9n", + "principal": { + "amount": "2000000000", + "denom": "usdx" + }, + "type": "xrpb-a" + }, + { + "accumulated_fees": { + "amount": "203160", + "denom": "usdx" + }, + "collateral": { + "amount": "149999900000", + "denom": "xrpb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1740", + "owner": "kava1h346y43zgpuexpdanq5850e4kktq0dcy4tfxd4", + "principal": { + "amount": "164645345", + "denom": "usdx" + }, + "type": "xrpb-a" + }, + { + "accumulated_fees": { + "amount": "1730077", + "denom": "usdx" + }, + "collateral": { + "amount": "1000914340000", + "denom": "xrpb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1756", + "owner": "kava1eu0s5hs52f4z8ld0hw3kuuwn07cgzauyda55n9", + "principal": { + "amount": "1236365778", + "denom": "usdx" + }, + "type": "xrpb-a" + }, + { + "accumulated_fees": { + "amount": "1000082", + "denom": "usdx" + }, + "collateral": { + "amount": "606339600000", + "denom": "xrpb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1834", + "owner": "kava15aemgl7ymdqc80wczqynms2wz0efvsf4hs0dhj", + "principal": { + "amount": "1935202227", + "denom": "usdx" + }, + "type": "xrpb-a" + }, + { + "accumulated_fees": { + "amount": "32371", + "denom": "usdx" + }, + "collateral": { + "amount": "59231000000", + "denom": "xrpb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1884", + "owner": "kava1t2u6mhqng5tkwkvjkj8fcp7szq2lkaffydwh2j", + "principal": { + "amount": "132328516", + "denom": "usdx" + }, + "type": "xrpb-a" + }, + { + "accumulated_fees": { + "amount": "211052", + "denom": "usdx" + }, + "collateral": { + "amount": "2802099800000", + "denom": "xrpb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1885", + "owner": "kava1alt4u48umfqgx6uwuhvu5qts67t78p86ejlv5y", + "principal": { + "amount": "9002590436", + "denom": "usdx" + }, + "type": "xrpb-a" + }, + { + "accumulated_fees": { + "amount": "34474", + "denom": "usdx" + }, + "collateral": { + "amount": "359290500000", + "denom": "xrpb" + }, + "fees_updated": "2020-12-01T19:07:23.449287085Z", + "id": "1899", + "owner": "kava1rea6zxqq78klh7uhf78juqp9nmtl53j7hsnquk", + "principal": { + "amount": "1149824431", + "denom": "usdx" + }, + "type": "xrpb-a" + } + ], + "debt_denom": "debt", + "deposits": [ + { + "amount": { + "amount": "1499799998000", + "denom": "bnb" + }, + "cdp_id": "2", + "depositor": "kava19txnej5reyyun4cadgq3kt7ynwpew364kuvfuu" + }, + { + "amount": { + "amount": "303353300", + "denom": "bnb" + }, + "cdp_id": "3", + "depositor": "kava1x0rpv6jgfk6yyrvjxp93wq2usjyy9pvl90yppz" + }, + { + "amount": { + "amount": "750046499", + "denom": "bnb" + }, + "cdp_id": "6", + "depositor": "kava1gzc54u4p67hh9r4m9vcml3ke9fc29tplvvaev3" + }, + { + "amount": { + "amount": "1121546242", + "denom": "bnb" + }, + "cdp_id": "8", + "depositor": "kava1nmvvhte2j225kvt0gssranmtzhcz50qyzecgsm" + }, + { + "amount": { + "amount": "533307948", + "denom": "bnb" + }, + "cdp_id": "9", + "depositor": "kava1qa5tpxdy9r636nt2ze76g8k5h6zce807z4tksg" + }, + { + "amount": { + "amount": "39341407849662", + "denom": "bnb" + }, + "cdp_id": "13", + "depositor": "kava12lsjquv3xrzyu27gyzuxtsmydk8akufznj8qsc" + }, + { + "amount": { + "amount": "68490588", + "denom": "bnb" + }, + "cdp_id": "17", + "depositor": "kava1rsla7s992jeyyaqzaszyljllrvnu6usssp802d" + }, + { + "amount": { + "amount": "1000000000", + "denom": "bnb" + }, + "cdp_id": "18", + "depositor": "kava1d6rxxma8uvneyda9fne4qzp7wxdd88vqu4x8qd" + }, + { + "amount": { + "amount": "25390911876", + "denom": "bnb" + }, + "cdp_id": "19", + "depositor": "kava1u4p6a2yse66ewfndw4j7ppsa777vdcex3m4n9s" + }, + { + "amount": { + "amount": "1089988748", + "denom": "bnb" + }, + "cdp_id": "20", + "depositor": "kava1w05lzr3tj72n33vam3v0qddq05hf605a6k92u5" + }, + { + "amount": { + "amount": "14550030222", + "denom": "bnb" + }, + "cdp_id": "21", + "depositor": "kava1ac6rmjtm8fy5du7twerkltwn20u6augkkuqngh" + }, + { + "amount": { + "amount": "88268546", + "denom": "bnb" + }, + "cdp_id": "22", + "depositor": "kava1e8xjfylam4nvugcmkxwvuxh22uvvad5vknu4yh" + }, + { + "amount": { + "amount": "7999984500", + "denom": "bnb" + }, + "cdp_id": "23", + "depositor": "kava1rea6zxqq78klh7uhf78juqp9nmtl53j7hsnquk" + }, + { + "amount": { + "amount": "79993000", + "denom": "bnb" + }, + "cdp_id": "24", + "depositor": "kava14pxuw9zzug0yvmevfzqas792mtnlmtqkc3uups" + }, + { + "amount": { + "amount": "100123000", + "denom": "bnb" + }, + "cdp_id": "25", + "depositor": "kava1kajy6ha74la3t7z8xhketrgd5a6jvlu7lhdw2f" + }, + { + "amount": { + "amount": "1099985500", + "denom": "bnb" + }, + "cdp_id": "26", + "depositor": "kava1r8jvmxp6hgu4qh3wevs6c06vyfy5gx0eh2amx8" + }, + { + "amount": { + "amount": "11332962000", + "denom": "bnb" + }, + "cdp_id": "27", + "depositor": "kava1q6l5a3ar2la208ekmj6cknk4k787l3anz8r9n0" + }, + { + "amount": { + "amount": "45478373051", + "denom": "bnb" + }, + "cdp_id": "28", + "depositor": "kava1dpcgtp7hjvspg7nxpj7c7j25lnyyrau0g72jkd" + }, + { + "amount": { + "amount": "16226006196", + "denom": "bnb" + }, + "cdp_id": "29", + "depositor": "kava15m5rxv4fut3766luadmxsrxljcs9fvy4afml3f" + }, + { + "amount": { + "amount": "122733500", + "denom": "bnb" + }, + "cdp_id": "32", + "depositor": "kava17xg8s04tmy57rzhfyfe5ec5xgypeqlpyeekc20" + }, + { + "amount": { + "amount": "184987000", + "denom": "bnb" + }, + "cdp_id": "33", + "depositor": "kava14702q7mchqfnnhgmqwrhrpj6lcnu4ahz43rg4l" + }, + { + "amount": { + "amount": "2628654500", + "denom": "bnb" + }, + "cdp_id": "36", + "depositor": "kava1en7rx4gygys7ah237vt2tq8wwph40mx9ulwu0s" + }, + { + "amount": { + "amount": "4157903615", + "denom": "bnb" + }, + "cdp_id": "37", + "depositor": "kava126fy66c0pnh76xlq54tw043u0hchacpeu0ytwy" + }, + { + "amount": { + "amount": "204696876", + "denom": "bnb" + }, + "cdp_id": "38", + "depositor": "kava1w0yg5qrrxg8s0ruxyw9e3qhxqtm5l3fk7pn3d9" + }, + { + "amount": { + "amount": "250000000", + "denom": "bnb" + }, + "cdp_id": "39", + "depositor": "kava1fcfus4u2zt8nr4srvm0g9xzh39r6m6qvp2kde3" + }, + { + "amount": { + "amount": "4999999000", + "denom": "bnb" + }, + "cdp_id": "40", + "depositor": "kava1cheyls7y2uj7yzmdjeeaaevz463n66ar5lrq8l" + }, + { + "amount": { + "amount": "11400761500", + "denom": "bnb" + }, + "cdp_id": "42", + "depositor": "kava1syhk5r2wrm8vtf6q4dtlu7eag2x74zp3zag0mj" + }, + { + "amount": { + "amount": "19852960968", + "denom": "bnb" + }, + "cdp_id": "43", + "depositor": "kava1hwww870p9wdhxs6kzv0x9eqdcp3p75wyqvmn7j" + }, + { + "amount": { + "amount": "19900000000", + "denom": "bnb" + }, + "cdp_id": "44", + "depositor": "kava1x7zvs79jzdyhr4h69vtkms2p7k8he4g3u43mym" + }, + { + "amount": { + "amount": "1399961500", + "denom": "bnb" + }, + "cdp_id": "45", + "depositor": "kava1w8lks5mcdvhvjjje9clhysel0j56qjfaudsvjk" + }, + { + "amount": { + "amount": "148000000", + "denom": "bnb" + }, + "cdp_id": "46", + "depositor": "kava1zyupq6ueyzexdc0qyspax9x3qg0tpkuqzv0l4w" + }, + { + "amount": { + "amount": "7908444605", + "denom": "bnb" + }, + "cdp_id": "47", + "depositor": "kava19jygxtwjal2eu3jmffaftvzwmflgq3gvusm5zl" + }, + { + "amount": { + "amount": "474914875", + "denom": "bnb" + }, + "cdp_id": "48", + "depositor": "kava1f46llpx6gna2erh3572krdlsugpxdpxa4mxwrs" + }, + { + "amount": { + "amount": "50009243000", + "denom": "bnb" + }, + "cdp_id": "49", + "depositor": "kava1fxxdrdrwaqlvatxc6ah2vg6dug72fmvcc4lz44" + }, + { + "amount": { + "amount": "2850785500", + "denom": "bnb" + }, + "cdp_id": "50", + "depositor": "kava1d5axvgqqx92af7pmmakc7x9z3whjrzaakqdmr3" + }, + { + "amount": { + "amount": "101472124", + "denom": "bnb" + }, + "cdp_id": "51", + "depositor": "kava1ajd3v4u8548mp5ffakhm523hr8auz5ztwqd9mm" + }, + { + "amount": { + "amount": "110666628", + "denom": "bnb" + }, + "cdp_id": "53", + "depositor": "kava1cpcs7j777fk2lmqkchz7d36d4k4upx0fjnsgpq" + }, + { + "amount": { + "amount": "75285412", + "denom": "bnb" + }, + "cdp_id": "54", + "depositor": "kava1rsmsfmjuzywp55aw50vf0u9tah0758z5z509e2" + }, + { + "amount": { + "amount": "1654546137", + "denom": "bnb" + }, + "cdp_id": "55", + "depositor": "kava1tpgwq3lzjn0fcs7lexx675pya4s6al5wvhcl8x" + }, + { + "amount": { + "amount": "615845000", + "denom": "bnb" + }, + "cdp_id": "56", + "depositor": "kava1ltctafhsemwxvdkeygn5dxcwumjg85vj5skrha" + }, + { + "amount": { + "amount": "593243069", + "denom": "bnb" + }, + "cdp_id": "57", + "depositor": "kava1pmxcrgrrp86rqdaane93s3659ulc8qqn2pe933" + }, + { + "amount": { + "amount": "700000000", + "denom": "bnb" + }, + "cdp_id": "58", + "depositor": "kava1ws3mcma3qfyq83ddg75p4e8h5xry7wufs5wt5r" + }, + { + "amount": { + "amount": "85011002", + "denom": "bnb" + }, + "cdp_id": "60", + "depositor": "kava1tzxxf6575nmvlwpqvshlad5uqv59arcs65us4a" + }, + { + "amount": { + "amount": "156822736", + "denom": "bnb" + }, + "cdp_id": "62", + "depositor": "kava15hz5fv6qmtjgukej5yc5axgzaklrwz32h5h96g" + }, + { + "amount": { + "amount": "253419438", + "denom": "bnb" + }, + "cdp_id": "65", + "depositor": "kava16mhvkn30xnpxxegcf5354udj3h6qqj8n4889sg" + }, + { + "amount": { + "amount": "11504824000", + "denom": "bnb" + }, + "cdp_id": "66", + "depositor": "kava1d6c4pv4f6vzp5egmxarese8kma8h8q4vh6edy9" + }, + { + "amount": { + "amount": "2599000000", + "denom": "bnb" + }, + "cdp_id": "67", + "depositor": "kava1a7vmnk0qfwuxq0jsek3hr798xutu24ga78s3ys" + }, + { + "amount": { + "amount": "240148621017", + "denom": "bnb" + }, + "cdp_id": "68", + "depositor": "kava1f98urpz5jj0tfhm0dy6dguk8qp4fq8yr7g0fyq" + }, + { + "amount": { + "amount": "50182925127", + "denom": "bnb" + }, + "cdp_id": "69", + "depositor": "kava18tt04xwqw38tcxplseymz8hyrgtd7tdpmlnt86" + }, + { + "amount": { + "amount": "100680062", + "denom": "bnb" + }, + "cdp_id": "74", + "depositor": "kava10zwxdhtwnagvx0lmj8jjzswrtuvutmap9gpsts" + }, + { + "amount": { + "amount": "67155552", + "denom": "bnb" + }, + "cdp_id": "75", + "depositor": "kava1qzsu6v4w3g9a8vwu67mcze7myjrnd75lwyk457" + }, + { + "amount": { + "amount": "110664667", + "denom": "bnb" + }, + "cdp_id": "77", + "depositor": "kava1s5le5df46lk8tehuqhyqj9tka5a9jpx0ym3f7l" + }, + { + "amount": { + "amount": "4971546794", + "denom": "bnb" + }, + "cdp_id": "81", + "depositor": "kava1mf3n0ym4eavgkcmazjx7v64a3a8x6nv3hrymdy" + }, + { + "amount": { + "amount": "99831345", + "denom": "bnb" + }, + "cdp_id": "82", + "depositor": "kava19q9us9uav8e2ua7zwlltmvgrhvr29nxttner5y" + }, + { + "amount": { + "amount": "225223570", + "denom": "bnb" + }, + "cdp_id": "83", + "depositor": "kava1evptartvf3mza08d3782wfdd24l8jzukrsuf44" + }, + { + "amount": { + "amount": "10317150541", + "denom": "bnb" + }, + "cdp_id": "84", + "depositor": "kava18jsynppwggcy6pde2t43ntsx45rh7e6a5dppc2" + }, + { + "amount": { + "amount": "4599998000", + "denom": "bnb" + }, + "cdp_id": "86", + "depositor": "kava1fts25suh92la0hal4qlsh2799xg43phrnyrle4" + }, + { + "amount": { + "amount": "594648617", + "denom": "bnb" + }, + "cdp_id": "87", + "depositor": "kava1hsf53nfvxng5sd77hgkt0kam0t5e33xucs3apx" + }, + { + "amount": { + "amount": "534886500", + "denom": "bnb" + }, + "cdp_id": "88", + "depositor": "kava1dmhhw04s4mlrsu35rn5y5xuyxx5zumuxg4pptw" + }, + { + "amount": { + "amount": "292902982", + "denom": "bnb" + }, + "cdp_id": "90", + "depositor": "kava1mazzh08dgdqrn8y6khq7snr9jgun3vtlzdhq7c" + }, + { + "amount": { + "amount": "97122198", + "denom": "bnb" + }, + "cdp_id": "92", + "depositor": "kava1wwalendqyqytsv2w6gqhpqu0hl4ewlxhadvl58" + }, + { + "amount": { + "amount": "4135994500", + "denom": "bnb" + }, + "cdp_id": "93", + "depositor": "kava17mr4tfdx9j6us9efl09esrcmw5tcg2d6ttjk6s" + }, + { + "amount": { + "amount": "5000000000", + "denom": "bnb" + }, + "cdp_id": "94", + "depositor": "kava179ahnk902wgm7qzr66t5ga0a8euc28ce703jy3" + }, + { + "amount": { + "amount": "2300000000", + "denom": "bnb" + }, + "cdp_id": "97", + "depositor": "kava1jl2cf6u0q0g6a64qtsyr340kntysq6v8yrzpk8" + }, + { + "amount": { + "amount": "106405225", + "denom": "bnb" + }, + "cdp_id": "100", + "depositor": "kava1kpdtvxkzmrlhjnkrrlz546pwlu5yp6q7l0wg9v" + }, + { + "amount": { + "amount": "5999823000", + "denom": "bnb" + }, + "cdp_id": "102", + "depositor": "kava13sljazg7hetghz33gsr9dmf5x90aj8qt3k7zdn" + }, + { + "amount": { + "amount": "172730500", + "denom": "bnb" + }, + "cdp_id": "107", + "depositor": "kava1txgtjvm8nvrmtxvvwrasuer54d4urxplvt49fd" + }, + { + "amount": { + "amount": "2999724000", + "denom": "bnb" + }, + "cdp_id": "109", + "depositor": "kava1wkn6z4xjrl2esflpdvxemn0m8hkv34ygh6xeaf" + }, + { + "amount": { + "amount": "201550019000", + "denom": "bnb" + }, + "cdp_id": "111", + "depositor": "kava1z9v59sdu65z4hssvhhhpnw0pz9p8y3kfgh0h3p" + }, + { + "amount": { + "amount": "8324185472", + "denom": "bnb" + }, + "cdp_id": "112", + "depositor": "kava12aazneqltthrxwkc3g4njhwgg9prjylst4m5uh" + }, + { + "amount": { + "amount": "173526945", + "denom": "bnb" + }, + "cdp_id": "114", + "depositor": "kava1p9plfdwvmzzdsjpukpmvvfh59n94nawzc83jlc" + }, + { + "amount": { + "amount": "199999000", + "denom": "bnb" + }, + "cdp_id": "115", + "depositor": "kava1pnh2qs7zfm46chg6k3yy8pad0wuf3rw75rk075" + }, + { + "amount": { + "amount": "82988091", + "denom": "bnb" + }, + "cdp_id": "116", + "depositor": "kava1njys2va5d4th3h6vfrspj7c2plmu8k7r7mc4kt" + }, + { + "amount": { + "amount": "200962500", + "denom": "bnb" + }, + "cdp_id": "117", + "depositor": "kava1uw6dj6dmrzp0rw02sy7rk9yqqncu7flf28ku0u" + }, + { + "amount": { + "amount": "13711077897", + "denom": "bnb" + }, + "cdp_id": "118", + "depositor": "kava1m33vlnaxcrpn43vrsdwa0er6gljek75297g0c6" + }, + { + "amount": { + "amount": "179999995", + "denom": "bnb" + }, + "cdp_id": "119", + "depositor": "kava1wg6awxhucnrp7672vcrxq88uwas7gdlsljxfne" + }, + { + "amount": { + "amount": "2561224250", + "denom": "bnb" + }, + "cdp_id": "120", + "depositor": "kava1kr7cckmy23tlj4d5urnsclsvxsagusn7kzqs3p" + }, + { + "amount": { + "amount": "12699898000", + "denom": "bnb" + }, + "cdp_id": "121", + "depositor": "kava1htrxzxfyek3n62d0jxcygeqflwkmvwslacrr74" + }, + { + "amount": { + "amount": "245854314", + "denom": "bnb" + }, + "cdp_id": "122", + "depositor": "kava1xspqeczcwpcj7ts3udyxstt33dhc28s0c9ekkx" + }, + { + "amount": { + "amount": "46580963451", + "denom": "bnb" + }, + "cdp_id": "125", + "depositor": "kava15aemgl7ymdqc80wczqynms2wz0efvsf4hs0dhj" + }, + { + "amount": { + "amount": "4878087619", + "denom": "bnb" + }, + "cdp_id": "126", + "depositor": "kava1z0u0efzn8llallan08kenpuj262etz9392phf4" + }, + { + "amount": { + "amount": "66759508", + "denom": "bnb" + }, + "cdp_id": "127", + "depositor": "kava14p5fs6wrqvm0sf908e4f439m3fn54v78em4fl2" + }, + { + "amount": { + "amount": "1250511274", + "denom": "bnb" + }, + "cdp_id": "128", + "depositor": "kava1cvg39q0es6npwwaazzvd3hwme8suf0zj2zjft8" + }, + { + "amount": { + "amount": "136428994", + "denom": "bnb" + }, + "cdp_id": "130", + "depositor": "kava1mdm5595gw7n2yrfa6fjdrk2xwzn4njkj2akvq4" + }, + { + "amount": { + "amount": "5893653156", + "denom": "bnb" + }, + "cdp_id": "131", + "depositor": "kava1lat5vnu7qj6wlhlqcvevd2q8euy6z5kwqqhk33" + }, + { + "amount": { + "amount": "130892506", + "denom": "bnb" + }, + "cdp_id": "132", + "depositor": "kava1n3wyrlf89nh0r8ckfum3xa9gjtvpus3ffeh9mw" + }, + { + "amount": { + "amount": "506477381", + "denom": "bnb" + }, + "cdp_id": "135", + "depositor": "kava12g2hjsf6wgxv72jepy7n6vv7t30jqy0ev798ys" + }, + { + "amount": { + "amount": "688712887", + "denom": "bnb" + }, + "cdp_id": "138", + "depositor": "kava1yp870cqtd52augmyqqnnzyn43p20jvtz0jttj9" + }, + { + "amount": { + "amount": "2199861500", + "denom": "bnb" + }, + "cdp_id": "139", + "depositor": "kava16h4qwf5gjuvhnaj4hn943gc6z5smvg07y3p4g0" + }, + { + "amount": { + "amount": "536961500", + "denom": "bnb" + }, + "cdp_id": "140", + "depositor": "kava1rsan6tsut8upy9m4xq3jjprkg5g7td7d5n7t9a" + }, + { + "amount": { + "amount": "15599923510", + "denom": "bnb" + }, + "cdp_id": "141", + "depositor": "kava1acqutt8qfe66c0nnhlzl7rmadfnuxnuaetehfh" + }, + { + "amount": { + "amount": "11919078365", + "denom": "bnb" + }, + "cdp_id": "142", + "depositor": "kava1xjqgqjx0qty6usulkl5qs9fphtysjx3zkmz0aj" + }, + { + "amount": { + "amount": "7539967934", + "denom": "bnb" + }, + "cdp_id": "143", + "depositor": "kava1sxhs7nrnmz5ypxjjx809wk92wy3uwz0x456r8w" + }, + { + "amount": { + "amount": "1999884500", + "denom": "bnb" + }, + "cdp_id": "144", + "depositor": "kava12aw587tn9nmmlvnq920hj9ykxewazhszjjrvtj" + }, + { + "amount": { + "amount": "200111925", + "denom": "bnb" + }, + "cdp_id": "146", + "depositor": "kava1k4p64mj6mumgqtj69h632qyhhy3ycx0hd9rmcn" + }, + { + "amount": { + "amount": "129890177", + "denom": "bnb" + }, + "cdp_id": "147", + "depositor": "kava1mmk5cms47rwr3dhmc5c5glquhzqphl4tz0k2ch" + }, + { + "amount": { + "amount": "4790000000", + "denom": "bnb" + }, + "cdp_id": "148", + "depositor": "kava1ftc84gde38ar4n94qw27hqngmfjgnhkz7vcue2" + }, + { + "amount": { + "amount": "157840000", + "denom": "bnb" + }, + "cdp_id": "150", + "depositor": "kava1ta5r404ddf3eg469feyp3vufvjrjzrwl32tztm" + }, + { + "amount": { + "amount": "98999000", + "denom": "bnb" + }, + "cdp_id": "152", + "depositor": "kava14n35k79dd8v0uvnrv78mlyu9z7ms3xvvxmgqp9" + }, + { + "amount": { + "amount": "186803826", + "denom": "bnb" + }, + "cdp_id": "155", + "depositor": "kava1d6zryvkfx9ee8l8xtjxq3l084zjunygjahj5a6" + }, + { + "amount": { + "amount": "13098997000", + "denom": "bnb" + }, + "cdp_id": "156", + "depositor": "kava1pmevzvgte6ktrr6lrpmqhd99gwd56dldcshlcs" + }, + { + "amount": { + "amount": "4514000000", + "denom": "bnb" + }, + "cdp_id": "157", + "depositor": "kava1d4053k27uwemf05wjzd8jwgce872jadk24g6zc" + }, + { + "amount": { + "amount": "506296525", + "denom": "bnb" + }, + "cdp_id": "158", + "depositor": "kava19c3nfs44hnvj79nhlgnejc72l3rehetjdeg22u" + }, + { + "amount": { + "amount": "219831500", + "denom": "bnb" + }, + "cdp_id": "161", + "depositor": "kava1umpnjpmarpf0zhplq2lmfvfftzzc9n5j8dl5wr" + }, + { + "amount": { + "amount": "1239861500", + "denom": "bnb" + }, + "cdp_id": "164", + "depositor": "kava14cu4p23z8hmdaxgsf4kw5umdwavlag0e575rqw" + }, + { + "amount": { + "amount": "8632985000", + "denom": "bnb" + }, + "cdp_id": "165", + "depositor": "kava1m37v42df7s50lh9l7rfa8wr6wffply4kzluvr0" + }, + { + "amount": { + "amount": "95333866", + "denom": "bnb" + }, + "cdp_id": "166", + "depositor": "kava1lwqsm6rlctyy4kyy46k9637zdmuscpr8p7faz5" + }, + { + "amount": { + "amount": "225000000", + "denom": "bnb" + }, + "cdp_id": "168", + "depositor": "kava1xjtc2yk7v8tr7ulw85s7x04z255h70h8rp49hq" + }, + { + "amount": { + "amount": "14492501291", + "denom": "bnb" + }, + "cdp_id": "169", + "depositor": "kava1au4duea0pe6a5dyzt5gfx6x449k6emqz0nczhl" + }, + { + "amount": { + "amount": "200000000", + "denom": "bnb" + }, + "cdp_id": "170", + "depositor": "kava1094f93evptxeg9nl82pn5wv2yrhqglqpq4wyvf" + }, + { + "amount": { + "amount": "105000000", + "denom": "bnb" + }, + "cdp_id": "172", + "depositor": "kava1twq0lv44v9hl3zl2v2799pnndr60w6g348ayxd" + }, + { + "amount": { + "amount": "129000000", + "denom": "bnb" + }, + "cdp_id": "173", + "depositor": "kava17kwqz4r3fnh4cderhza8lnq63su4drfzeqra7m" + }, + { + "amount": { + "amount": "4457745351", + "denom": "bnb" + }, + "cdp_id": "174", + "depositor": "kava1ljex7663xnw98455y4fgtref0znkt2u0yglh6k" + }, + { + "amount": { + "amount": "199961500", + "denom": "bnb" + }, + "cdp_id": "177", + "depositor": "kava1wgtny83g504gxpfj0f36cx6ztrfqlk0wj4pese" + }, + { + "amount": { + "amount": "200181296", + "denom": "bnb" + }, + "cdp_id": "180", + "depositor": "kava12qgnr0f8v9q3uuzhpjudlw90v6map4pdu5cfdc" + }, + { + "amount": { + "amount": "700000000", + "denom": "bnb" + }, + "cdp_id": "183", + "depositor": "kava1wc4pmp258ns0rk2vvknjz5rwnpju378k82hhwd" + }, + { + "amount": { + "amount": "5624934939", + "denom": "bnb" + }, + "cdp_id": "184", + "depositor": "kava1hfmx6fngjmjuwvs3tmaev85dduq69w2jkchv8x" + }, + { + "amount": { + "amount": "1382979946", + "denom": "bnb" + }, + "cdp_id": "185", + "depositor": "kava13tzqh4zcdu8t87zhc9dz9jvre788mv53h9kcgr" + }, + { + "amount": { + "amount": "132265818", + "denom": "bnb" + }, + "cdp_id": "186", + "depositor": "kava1htlex570h6jy97g7dt6t254gt8g8p06s6re6rx" + }, + { + "amount": { + "amount": "99861500", + "denom": "bnb" + }, + "cdp_id": "188", + "depositor": "kava1x6vr5x2ln3t8p0v75d25j2levjzjs26rvzfm69" + }, + { + "amount": { + "amount": "3899760500", + "denom": "bnb" + }, + "cdp_id": "194", + "depositor": "kava1la226f3y75shcn7ath84h3wqft3az4qqf9sd2m" + }, + { + "amount": { + "amount": "240000000", + "denom": "bnb" + }, + "cdp_id": "195", + "depositor": "kava1hrhn3kpm3euny5u7ua783enyzjm27mf2l6l9rh" + }, + { + "amount": { + "amount": "363621435", + "denom": "bnb" + }, + "cdp_id": "196", + "depositor": "kava1667fn3eu2r57uj6w8t4zpz7rak73kawxqtujpm" + }, + { + "amount": { + "amount": "33404315684", + "denom": "bnb" + }, + "cdp_id": "198", + "depositor": "kava1v3atcfl7hmesuwdp8s7rshveuynqkx0vdqvs2l" + }, + { + "amount": { + "amount": "152505102000", + "denom": "bnb" + }, + "cdp_id": "199", + "depositor": "kava1mz2vfw29fzkg4yj9wfh99nkgx46unhrxtyxqhc" + }, + { + "amount": { + "amount": "2500000000", + "denom": "bnb" + }, + "cdp_id": "201", + "depositor": "kava175mrr57z7t3kr7mgxc5rut244nsl4y69ynaak2" + }, + { + "amount": { + "amount": "4109955500", + "denom": "bnb" + }, + "cdp_id": "209", + "depositor": "kava1egcn53hpwr73yqrl927gjrrxmjsu3nz74km58n" + }, + { + "amount": { + "amount": "14332460104", + "denom": "bnb" + }, + "cdp_id": "210", + "depositor": "kava1zdlmh3s8wea9xsjk59n3fuy73lw4wn435dw80j" + }, + { + "amount": { + "amount": "97950382500", + "denom": "bnb" + }, + "cdp_id": "212", + "depositor": "kava12qjltp2vkqmpp29s97l3esk2ek5zjsl9lnlfj4" + }, + { + "amount": { + "amount": "630788993", + "denom": "bnb" + }, + "cdp_id": "214", + "depositor": "kava17qau97j220xw0ssptvh7vnl4wqak6e2pgtne35" + }, + { + "amount": { + "amount": "6605883474", + "denom": "bnb" + }, + "cdp_id": "220", + "depositor": "kava1lq0aggmkh3nk5zuzwsv5g2pph9cp0xl4vuh4t7" + }, + { + "amount": { + "amount": "137861617", + "denom": "bnb" + }, + "cdp_id": "221", + "depositor": "kava1fewhhjak24u0s54jw9s7pdluw2aqw4cra2el42" + }, + { + "amount": { + "amount": "181855384467", + "denom": "bnb" + }, + "cdp_id": "223", + "depositor": "kava14m0dtdvs9pqeqg74g7jnxcr9tkpl4maa7r5mkv" + }, + { + "amount": { + "amount": "2045659746", + "denom": "bnb" + }, + "cdp_id": "224", + "depositor": "kava1jzfled0eeaalypkzj6p5dmesav2va3tfzaa8cl" + }, + { + "amount": { + "amount": "84315550", + "denom": "bnb" + }, + "cdp_id": "225", + "depositor": "kava10qzu70ezk0rajhj6wrztt8y4lc556sqxmlc6mz" + }, + { + "amount": { + "amount": "29994238985", + "denom": "bnb" + }, + "cdp_id": "226", + "depositor": "kava1p8nd9vexkqhcenzj3cuju640q4zt35tdf0hk4g" + }, + { + "amount": { + "amount": "6034659040", + "denom": "bnb" + }, + "cdp_id": "228", + "depositor": "kava10tejts3kusudtpqfpv9rsxhealyfqs3q25zqk9" + }, + { + "amount": { + "amount": "13649307500", + "denom": "bnb" + }, + "cdp_id": "230", + "depositor": "kava1smm4h4uynsdq7ymahr7h4c89hdll8fpry742kp" + }, + { + "amount": { + "amount": "574537974", + "denom": "bnb" + }, + "cdp_id": "231", + "depositor": "kava1w20u97emzxc257hdyaywdxnyxs0mx586a5nxe2" + }, + { + "amount": { + "amount": "199861500", + "denom": "bnb" + }, + "cdp_id": "233", + "depositor": "kava10ucdtdqqnkhh26z4zqk6ewwp2ld03etkzeskcz" + }, + { + "amount": { + "amount": "89999000", + "denom": "bnb" + }, + "cdp_id": "236", + "depositor": "kava1sfj08ymeqfevqk8w3fmhrm8fmdc9dqa8ew0egu" + }, + { + "amount": { + "amount": "5199723000", + "denom": "bnb" + }, + "cdp_id": "238", + "depositor": "kava1gqfh80j9fe95hczvew62d527agntsp7je4ddrw" + }, + { + "amount": { + "amount": "21009884500", + "denom": "bnb" + }, + "cdp_id": "240", + "depositor": "kava18utzytkj0unzevcm4jzxncu95prc8x5wqcnt9n" + }, + { + "amount": { + "amount": "5078401785", + "denom": "bnb" + }, + "cdp_id": "241", + "depositor": "kava1cfyddlz92xuk73kp5du820eu4h92fy3rs85k4w" + }, + { + "amount": { + "amount": "40636064040", + "denom": "bnb" + }, + "cdp_id": "242", + "depositor": "kava1fuwnpvv6heued9mmhlphpwgyu4fu0tzvcan9u9" + }, + { + "amount": { + "amount": "1009997000", + "denom": "bnb" + }, + "cdp_id": "243", + "depositor": "kava1zax5vgs3u9tn64puy7jg0a9tt4h7l652p2qjjn" + }, + { + "amount": { + "amount": "1101467619", + "denom": "bnb" + }, + "cdp_id": "244", + "depositor": "kava1f00asq9t4fmvmy3n5p950t8njq3vptdgmfg62v" + }, + { + "amount": { + "amount": "29699823000", + "denom": "bnb" + }, + "cdp_id": "245", + "depositor": "kava1jvggf4u68jvlm4dk3auh4ns2fuuph2w2yr7utf" + }, + { + "amount": { + "amount": "142899949000", + "denom": "bnb" + }, + "cdp_id": "246", + "depositor": "kava1vn75l627k2p97wzu2sl3mhsxj285lvyrp4z866" + }, + { + "amount": { + "amount": "889998000", + "denom": "bnb" + }, + "cdp_id": "247", + "depositor": "kava1wyqhajn6mshcmx0j5qqzdmd87c7a83c5f4c587" + }, + { + "amount": { + "amount": "4732418000", + "denom": "bnb" + }, + "cdp_id": "248", + "depositor": "kava1lmdqakjz5p7gjw3q7333kkgc2xje4d6zzu544k" + }, + { + "amount": { + "amount": "100009998000", + "denom": "bnb" + }, + "cdp_id": "249", + "depositor": "kava10f52vl8ga9map8pjlyeypglcrd9yxnn503gfuh" + }, + { + "amount": { + "amount": "10000000000", + "denom": "bnb" + }, + "cdp_id": "250", + "depositor": "kava1q56vft29tyu64lr24mj9rehxgdvrskj8puyjx5" + }, + { + "amount": { + "amount": "102126763500", + "denom": "bnb" + }, + "cdp_id": "251", + "depositor": "kava1u205gp2kxm7kj2ta2yhtpazdyc97xgy8e3re7k" + }, + { + "amount": { + "amount": "8297257199", + "denom": "bnb" + }, + "cdp_id": "252", + "depositor": "kava1hfqe298wulu4uhqgj0h8sggc3akrgyelavzszv" + }, + { + "amount": { + "amount": "30149861500", + "denom": "bnb" + }, + "cdp_id": "253", + "depositor": "kava1k33pgvv8fs875ht5erf4qvqpdrhtlckt2twd93" + }, + { + "amount": { + "amount": "2843220500", + "denom": "bnb" + }, + "cdp_id": "254", + "depositor": "kava1n7mfen688q8yy3ppwpl2maymtfrh5u2a8c7e33" + }, + { + "amount": { + "amount": "6497259922", + "denom": "bnb" + }, + "cdp_id": "255", + "depositor": "kava1ynemgmzp3mfevzj5e6zcg97z2dmjgvuysgzyyx" + }, + { + "amount": { + "amount": "860000000", + "denom": "bnb" + }, + "cdp_id": "256", + "depositor": "kava1vpvj0w7spgzx4rkhkv4j4y0tj58dc8endq99s6" + }, + { + "amount": { + "amount": "3789926071", + "denom": "bnb" + }, + "cdp_id": "257", + "depositor": "kava1mfc7p3yt6r33qsee677wlwa4zr5u09sdex8txt" + }, + { + "amount": { + "amount": "101644000", + "denom": "bnb" + }, + "cdp_id": "259", + "depositor": "kava1a50y5udh2knhktmxyczl349a96zpngjvzqrkzu" + }, + { + "amount": { + "amount": "129924000", + "denom": "bnb" + }, + "cdp_id": "260", + "depositor": "kava1vqcufyyah03sntzgsz6rfykjtrsfguht2hgw6d" + }, + { + "amount": { + "amount": "2198824000", + "denom": "bnb" + }, + "cdp_id": "261", + "depositor": "kava1cerh3sw0m2mpnwdz3a930qd5d7n5nz8s8f4p6w" + }, + { + "amount": { + "amount": "499961500", + "denom": "bnb" + }, + "cdp_id": "262", + "depositor": "kava1c5he6km22u7upezmuj3yzvwu6a3u2vmnaunp8d" + }, + { + "amount": { + "amount": "161543210", + "denom": "bnb" + }, + "cdp_id": "265", + "depositor": "kava1gupd5xrnzsaln387044z39lrclxnrjxg2s0rza" + }, + { + "amount": { + "amount": "163644000", + "denom": "bnb" + }, + "cdp_id": "266", + "depositor": "kava1jdvt0v2l5mcpmasd2zjk8zpxwkk78a8rfkds0p" + }, + { + "amount": { + "amount": "30100000000", + "denom": "bnb" + }, + "cdp_id": "268", + "depositor": "kava1m520r5q3t9qug3ssc52wc9s0876c7v9dde5d6k" + }, + { + "amount": { + "amount": "269999000", + "denom": "bnb" + }, + "cdp_id": "269", + "depositor": "kava1w5f7v8wa8jxg9f2c6scufgs7r9gl7npsh570n7" + }, + { + "amount": { + "amount": "677627000", + "denom": "bnb" + }, + "cdp_id": "271", + "depositor": "kava1qxhh4g05dckdzjhe592kv82t50dh9l4ds4ljlm" + }, + { + "amount": { + "amount": "799273233", + "denom": "bnb" + }, + "cdp_id": "272", + "depositor": "kava19qd98v0twgum4eqln8gcwru8wccv2syu7rcygk" + }, + { + "amount": { + "amount": "8960753805", + "denom": "bnb" + }, + "cdp_id": "273", + "depositor": "kava1mxu3lnm80ynhs2gavu2w2um29pcvkgvceh29ks" + }, + { + "amount": { + "amount": "3397860720", + "denom": "bnb" + }, + "cdp_id": "274", + "depositor": "kava1qg53ggjzzz8e9x9kh9fsk8a4z2dldczrp6j00l" + }, + { + "amount": { + "amount": "1762359738", + "denom": "bnb" + }, + "cdp_id": "275", + "depositor": "kava1tss7dhwa533u8h3v8z43w8656uaxk3fvzhrwzj" + }, + { + "amount": { + "amount": "709861500", + "denom": "bnb" + }, + "cdp_id": "276", + "depositor": "kava1j8ecw7df2t57d0s5qpk8ke2f6d6m7rhuf4mkva" + }, + { + "amount": { + "amount": "99861500", + "denom": "bnb" + }, + "cdp_id": "277", + "depositor": "kava1wxvryaw030wwmp3a588wnehwqp9wlv0zn460ek" + }, + { + "amount": { + "amount": "8320342399", + "denom": "bnb" + }, + "cdp_id": "278", + "depositor": "kava184kqpjfpycyza900d7q3gx8nhxt5e0syqmg49w" + }, + { + "amount": { + "amount": "1684599000", + "denom": "bnb" + }, + "cdp_id": "279", + "depositor": "kava1gjxu07sy6cmdxd8gwpqv4ry3epeuszvpkl9p82" + }, + { + "amount": { + "amount": "1999961500", + "denom": "bnb" + }, + "cdp_id": "280", + "depositor": "kava1mzt56dpf2d0gdrzarf7p6kd8nnjkpc25fuc3r5" + }, + { + "amount": { + "amount": "35806987133", + "denom": "bnb" + }, + "cdp_id": "281", + "depositor": "kava16v8kqpw58lmh6pl2wggyheh3pxe7uenzm478ye" + }, + { + "amount": { + "amount": "84999000", + "denom": "bnb" + }, + "cdp_id": "282", + "depositor": "kava1gwjt5vxekyxfdgrmyewwkr6uyvj87tfa0mzx2v" + }, + { + "amount": { + "amount": "86914598", + "denom": "bnb" + }, + "cdp_id": "284", + "depositor": "kava1xm5h5v6kwydahmrst577fj3s7u3e5gjwecy5zg" + }, + { + "amount": { + "amount": "2499961500", + "denom": "bnb" + }, + "cdp_id": "285", + "depositor": "kava1v6dnz6206d38s729jjewekfz8kyk08m702gr4r" + }, + { + "amount": { + "amount": "7999961500", + "denom": "bnb" + }, + "cdp_id": "286", + "depositor": "kava14qv83m9csmul9qdgqyafqhhwha8z464s5ppjta" + }, + { + "amount": { + "amount": "4499908828", + "denom": "bnb" + }, + "cdp_id": "287", + "depositor": "kava1tuulhc6twgdtvzd6685ltqgh2adjcuyaxzkyvk" + }, + { + "amount": { + "amount": "4499584500", + "denom": "bnb" + }, + "cdp_id": "288", + "depositor": "kava1q2hpn8wjvgygwf8uvtlm99x7jr4az87gu0und9" + }, + { + "amount": { + "amount": "99861500", + "denom": "bnb" + }, + "cdp_id": "289", + "depositor": "kava1yj79c8l6rmrnd9kwga9ruetaseh2yxv2f6xe7y" + }, + { + "amount": { + "amount": "490000000", + "denom": "bnb" + }, + "cdp_id": "290", + "depositor": "kava1ks9u07zl4h3h3q6mlu4t2v7xflwvk332rz8m33" + }, + { + "amount": { + "amount": "249861500", + "denom": "bnb" + }, + "cdp_id": "292", + "depositor": "kava1kttpakv8zy8h3q8fc2665rk5k0jj0v4g3d3tsy" + }, + { + "amount": { + "amount": "118092975", + "denom": "bnb" + }, + "cdp_id": "293", + "depositor": "kava1acmwmx66s0htudhn43jgdym0xdphyvnhez6jky" + }, + { + "amount": { + "amount": "1499861500", + "denom": "bnb" + }, + "cdp_id": "294", + "depositor": "kava1dn23hf3h0ysfh8j6t7f6vp95unvfet7qlgrkv4" + }, + { + "amount": { + "amount": "139799581", + "denom": "bnb" + }, + "cdp_id": "295", + "depositor": "kava1jdf8d4s0zcwtg5le0qkya0xsfl85xm4zpv4802" + }, + { + "amount": { + "amount": "3489084250", + "denom": "bnb" + }, + "cdp_id": "296", + "depositor": "kava19r2a7ewaknnp60nvz78f60xqlszlw3msgscg8f" + }, + { + "amount": { + "amount": "100000000", + "denom": "bnb" + }, + "cdp_id": "297", + "depositor": "kava1uaz20kn9qnf23kcj9tne2glfs4d7vtwt0c66ws" + }, + { + "amount": { + "amount": "20062220557", + "denom": "bnb" + }, + "cdp_id": "299", + "depositor": "kava1rdzc5h94tjfsg38se9zre672z9ccux06ywdlme" + }, + { + "amount": { + "amount": "98253652312", + "denom": "bnb" + }, + "cdp_id": "300", + "depositor": "kava1d2u28azje7rhqyjtxc2ex8q0cxxpw7dfm7ltq5" + }, + { + "amount": { + "amount": "1363949000", + "denom": "bnb" + }, + "cdp_id": "301", + "depositor": "kava1knu3dygrpnfy92kxqwh0mv3pzylfug6nwk68pd" + }, + { + "amount": { + "amount": "199961500", + "denom": "bnb" + }, + "cdp_id": "302", + "depositor": "kava1a33hz0z6wr728gfy9mf80lhgngdqm28l94n9ej" + }, + { + "amount": { + "amount": "200000000", + "denom": "bnb" + }, + "cdp_id": "303", + "depositor": "kava1yzmdt6hgpcs8q2tmasls5fksrx8fl78ddj3nzn" + }, + { + "amount": { + "amount": "4081136101", + "denom": "bnb" + }, + "cdp_id": "306", + "depositor": "kava17cptmd6cs2h032pg4jnjdlfjgvhnkcl32evqy3" + }, + { + "amount": { + "amount": "14999961500", + "denom": "bnb" + }, + "cdp_id": "308", + "depositor": "kava1ujpxleqcqugjdulwne6z0du8f5mej55c545pfz" + }, + { + "amount": { + "amount": "61811997", + "denom": "bnb" + }, + "cdp_id": "310", + "depositor": "kava1ym6nku4uur3vz0lp3ur54dkhpll8uhehgfnz8k" + }, + { + "amount": { + "amount": "2294885500", + "denom": "bnb" + }, + "cdp_id": "311", + "depositor": "kava12dh2n57a0yq5tp4neux9zk9w62z6hg58gwuta2" + }, + { + "amount": { + "amount": "92858000", + "denom": "bnb" + }, + "cdp_id": "312", + "depositor": "kava1r24w3dl5jxke3lt5x5jc2cvjlp97ynmhve8x8e" + }, + { + "amount": { + "amount": "2634033895", + "denom": "bnb" + }, + "cdp_id": "314", + "depositor": "kava1dv0zgqn33sjyyx7jhxt3s9c2ug239t8fnph42q" + }, + { + "amount": { + "amount": "999115120", + "denom": "bnb" + }, + "cdp_id": "315", + "depositor": "kava1yw26hjjy88k4ym5ntu2h6e55pgm2xp8sqy72sw" + }, + { + "amount": { + "amount": "203117060", + "denom": "bnb" + }, + "cdp_id": "316", + "depositor": "kava1rlr7nzssxt2ls2nnldey272alalsnf6svn4vyj" + }, + { + "amount": { + "amount": "7510761500", + "denom": "bnb" + }, + "cdp_id": "317", + "depositor": "kava109a56s0epqwe3emg9786kt7n5urnrscstk04ms" + }, + { + "amount": { + "amount": "111957402", + "denom": "bnb" + }, + "cdp_id": "319", + "depositor": "kava1dwlzzy9c4ge26xh95556pjp6lsg2e66wc64unl" + }, + { + "amount": { + "amount": "200061500", + "denom": "bnb" + }, + "cdp_id": "320", + "depositor": "kava1hxku2c2g4ngum33ewpgyk58wl9he9ces97nw3q" + }, + { + "amount": { + "amount": "6546967000", + "denom": "bnb" + }, + "cdp_id": "324", + "depositor": "kava1j25le44ttjsrvt5h6k56ytmcn7n50mltw6muxd" + }, + { + "amount": { + "amount": "12450000000", + "denom": "bnb" + }, + "cdp_id": "326", + "depositor": "kava17lgpxr5mug8hsmftzlklqyqtlu7mwpzwgqc0aq" + }, + { + "amount": { + "amount": "199861500", + "denom": "bnb" + }, + "cdp_id": "329", + "depositor": "kava12uq64q7k0fvwvly7latfvxgf4t09mpkfm6tg37" + }, + { + "amount": { + "amount": "75859266", + "denom": "bnb" + }, + "cdp_id": "330", + "depositor": "kava1resk3zjgyv9298u2ckkpdz38gekh9myqr6tk4a" + }, + { + "amount": { + "amount": "409995000", + "denom": "bnb" + }, + "cdp_id": "331", + "depositor": "kava1xxntzlrgekrk7nt9xdh5fk52c2kds2r0al5lmq" + }, + { + "amount": { + "amount": "22654997000", + "denom": "bnb" + }, + "cdp_id": "332", + "depositor": "kava1vg6q5k7q6s89lk852dgle8c5fr3rmrrr3jsvhy" + }, + { + "amount": { + "amount": "149928250", + "denom": "bnb" + }, + "cdp_id": "333", + "depositor": "kava1cf0ukvyjljkwld5gdx0gc6e3wf9wmyyundw8xa" + }, + { + "amount": { + "amount": "2000999000", + "denom": "bnb" + }, + "cdp_id": "334", + "depositor": "kava1uwwcahz5wxd5hyu2xpgxxpselkr6wmzf0q06lk" + }, + { + "amount": { + "amount": "70175305686", + "denom": "bnb" + }, + "cdp_id": "335", + "depositor": "kava16ug360rgcgd460046x97udcd9k0n39rze5qtp9" + }, + { + "amount": { + "amount": "914774583", + "denom": "bnb" + }, + "cdp_id": "336", + "depositor": "kava1j46re9mh9y63jldgy5g66e3jc0sk0wq6ze9ajl" + }, + { + "amount": { + "amount": "199998000", + "denom": "bnb" + }, + "cdp_id": "337", + "depositor": "kava1942dmaf9g8x3s9m6p64d5hsy49pdfa2ux9h205" + }, + { + "amount": { + "amount": "2179961500", + "denom": "bnb" + }, + "cdp_id": "338", + "depositor": "kava1wzqa96jrwda3szysudfsu7dzm64rcad2wj4z6w" + }, + { + "amount": { + "amount": "135208606", + "denom": "bnb" + }, + "cdp_id": "339", + "depositor": "kava1mka7zvjmznra0wn67f6tfppj0g07ddwznqnefm" + }, + { + "amount": { + "amount": "301902824", + "denom": "bnb" + }, + "cdp_id": "341", + "depositor": "kava19ftkymerpmf2lq427da377ypednatj467lc7wy" + }, + { + "amount": { + "amount": "4793394312", + "denom": "bnb" + }, + "cdp_id": "342", + "depositor": "kava1hndh9pwsaz5arhtryh8zedtr4kdvdtvcfnvc3d" + }, + { + "amount": { + "amount": "331427379", + "denom": "bnb" + }, + "cdp_id": "344", + "depositor": "kava1vmgk2zex6wm73hkuna9p9rm343e57xyznszfj7" + }, + { + "amount": { + "amount": "108004194", + "denom": "bnb" + }, + "cdp_id": "345", + "depositor": "kava1zqrpq7jaw9agqhh5e00gf28twfpc2ex05w8sec" + }, + { + "amount": { + "amount": "159961500", + "denom": "bnb" + }, + "cdp_id": "347", + "depositor": "kava1hwf9g5ffng96qmgr0lxzuyljgrc5ne7e0gk780" + }, + { + "amount": { + "amount": "302093000", + "denom": "bnb" + }, + "cdp_id": "349", + "depositor": "kava18remxg0pxfvrrfkez5lzjtaj6ldlq6hz0g9hy4" + }, + { + "amount": { + "amount": "122917493", + "denom": "bnb" + }, + "cdp_id": "350", + "depositor": "kava16p8lcgmjh6edz622935uvd7rufrl3jtafwdgg5" + }, + { + "amount": { + "amount": "134248000", + "denom": "bnb" + }, + "cdp_id": "351", + "depositor": "kava1tmz4v86u8j8cq8yxgh6lensugkzxpql4c7mpxy" + }, + { + "amount": { + "amount": "39099024500", + "denom": "bnb" + }, + "cdp_id": "353", + "depositor": "kava1jhjr5gef5dg3cyualy3um2rvn7594r3frtm39l" + }, + { + "amount": { + "amount": "9974999250", + "denom": "bnb" + }, + "cdp_id": "354", + "depositor": "kava1u5qymm9e7hlarv9g3lud68dtnay5nc0z29cwq6" + }, + { + "amount": { + "amount": "2159823000", + "denom": "bnb" + }, + "cdp_id": "355", + "depositor": "kava12yakv78pyls0axh5lnhaha6sk6azt29jj7jg46" + }, + { + "amount": { + "amount": "116515577", + "denom": "bnb" + }, + "cdp_id": "356", + "depositor": "kava1p2d5tqngkf0xmmaut5t3lvnwxk8r3jkesq4nav" + }, + { + "amount": { + "amount": "260136988", + "denom": "bnb" + }, + "cdp_id": "357", + "depositor": "kava16jug37mdmzmntrza48z6munagftushdncmx0ll" + }, + { + "amount": { + "amount": "72854000", + "denom": "bnb" + }, + "cdp_id": "359", + "depositor": "kava1szqdxulk2n8gy0wcf5k0gpxv6g9xfw7hq8gatx" + }, + { + "amount": { + "amount": "1900000000", + "denom": "bnb" + }, + "cdp_id": "360", + "depositor": "kava1daexlmcw6ef6v350pj65wgwd6d2s04t9krzhh6" + }, + { + "amount": { + "amount": "104667426", + "denom": "bnb" + }, + "cdp_id": "361", + "depositor": "kava1zpcj88j42nyfj4xett8lwdmvxwnlhljny9wcl8" + }, + { + "amount": { + "amount": "4999861500", + "denom": "bnb" + }, + "cdp_id": "363", + "depositor": "kava1zwkkhamrvr8fhr3e6cq7e9w56zm2g6d9qljqr7" + }, + { + "amount": { + "amount": "1073384000", + "denom": "bnb" + }, + "cdp_id": "364", + "depositor": "kava1u30dpd3h8mdwudrhlfj5uhwhpzlzq4z9k28e4a" + }, + { + "amount": { + "amount": "999999000", + "denom": "bnb" + }, + "cdp_id": "366", + "depositor": "kava13g63wevgyyvrgyjsuwqj3274aejh6kxruz50qg" + }, + { + "amount": { + "amount": "171209890", + "denom": "bnb" + }, + "cdp_id": "367", + "depositor": "kava1rldss49zjtc94a7nwn9y2pf7lnqr0c0lg8vhzr" + }, + { + "amount": { + "amount": "16825426911", + "denom": "bnb" + }, + "cdp_id": "368", + "depositor": "kava1p9fswn29klzkp5vws0mje2g4f4xdln55krv5vt" + }, + { + "amount": { + "amount": "1000000000", + "denom": "bnb" + }, + "cdp_id": "370", + "depositor": "kava1rytcgddazyzeytaumugwtmldfz7dzym3w8fuls" + }, + { + "amount": { + "amount": "408998000", + "denom": "bnb" + }, + "cdp_id": "371", + "depositor": "kava1zpxyy68uxylkdf25ap3cp0jc398xlxg0yj23kr" + }, + { + "amount": { + "amount": "56349766", + "denom": "bnb" + }, + "cdp_id": "372", + "depositor": "kava1hezl6xwva28xt0hk204dllalagenmfsn32w82d" + }, + { + "amount": { + "amount": "84697000", + "denom": "bnb" + }, + "cdp_id": "373", + "depositor": "kava1wdxsukxg0h2x7sgjcw23ahcn34sesv9k0m225u" + }, + { + "amount": { + "amount": "548999000", + "denom": "bnb" + }, + "cdp_id": "375", + "depositor": "kava15j9e4gffh6r98vsukd9zt5q2w8wtynfm3qx7qr" + }, + { + "amount": { + "amount": "190000000", + "denom": "bnb" + }, + "cdp_id": "376", + "depositor": "kava1vp35dt2p5y8tsnptdqdcyypzrmsnjgaq3k3e8g" + }, + { + "amount": { + "amount": "898890000", + "denom": "bnb" + }, + "cdp_id": "377", + "depositor": "kava190qjfrpwwvtkhmj4tefz86y2mx94yqgezkpdkx" + }, + { + "amount": { + "amount": "999961500", + "denom": "bnb" + }, + "cdp_id": "378", + "depositor": "kava1e228zg7qfcqed5c78z96rne0fee4f0xdkfhwjq" + }, + { + "amount": { + "amount": "119924000", + "denom": "bnb" + }, + "cdp_id": "379", + "depositor": "kava1djun9vdmqhay9llr3pl60pg8rfxamr2z4xlu68" + }, + { + "amount": { + "amount": "999961500", + "denom": "bnb" + }, + "cdp_id": "380", + "depositor": "kava1wwne8dzzdz4jjcjp2cmr4vwdqyhanqptrwm5lc" + }, + { + "amount": { + "amount": "56893201", + "denom": "bnb" + }, + "cdp_id": "381", + "depositor": "kava1w0ukaj52gcqeyudwrt0842c36syjzp79fza4wy" + }, + { + "amount": { + "amount": "2835741068", + "denom": "bnb" + }, + "cdp_id": "382", + "depositor": "kava1267c4ask3llkjny5876hc8qc4aasvxqxuje0kl" + }, + { + "amount": { + "amount": "2428242815", + "denom": "bnb" + }, + "cdp_id": "384", + "depositor": "kava1myy3lkcshgmg5ke7gj07mmsyuxf3wyazastnpl" + }, + { + "amount": { + "amount": "156294301", + "denom": "bnb" + }, + "cdp_id": "386", + "depositor": "kava138kzn55zekj6hydq5sqt53m2p2u479p6een8pd" + }, + { + "amount": { + "amount": "230151411", + "denom": "bnb" + }, + "cdp_id": "387", + "depositor": "kava183c3dft0zj5kqnvdxke4cdlt5qa8j47wxt0qd2" + }, + { + "amount": { + "amount": "149999923000", + "denom": "bnb" + }, + "cdp_id": "390", + "depositor": "kava1hnugk43fax68hp6csqymsjc9fpdvl6fn8mgr4y" + }, + { + "amount": { + "amount": "67098716", + "denom": "bnb" + }, + "cdp_id": "391", + "depositor": "kava1pmqrsde4l4t0pyxyn28uquk9e0ea83u0fa3t3r" + }, + { + "amount": { + "amount": "5099761500", + "denom": "bnb" + }, + "cdp_id": "393", + "depositor": "kava120hwpwxj22v4p4ehav96dkvl3sn5fcaqy04n2k" + }, + { + "amount": { + "amount": "7326829987", + "denom": "bnb" + }, + "cdp_id": "394", + "depositor": "kava1gnnxpwfht60gvttrs0kfh7qru49nqtyqnudnqw" + }, + { + "amount": { + "amount": "545762958", + "denom": "bnb" + }, + "cdp_id": "396", + "depositor": "kava1wuvxx8zeft7g88nazgjd4800fzuxhrm2rqs55x" + }, + { + "amount": { + "amount": "162468718", + "denom": "bnb" + }, + "cdp_id": "397", + "depositor": "kava1yp45n64cj059m55cpl5et3vl46h993a60g5jds" + }, + { + "amount": { + "amount": "8479261500", + "denom": "bnb" + }, + "cdp_id": "398", + "depositor": "kava1932gg48nkx0m5294gswdru76rvwwxfuj2s2cxx" + }, + { + "amount": { + "amount": "44899999000", + "denom": "bnb" + }, + "cdp_id": "399", + "depositor": "kava1zjw5ndqh6qkrld5f48w9l74ylftapfwudz5a3m" + }, + { + "amount": { + "amount": "254907989", + "denom": "bnb" + }, + "cdp_id": "400", + "depositor": "kava1wszz0ym34kstc66cn23jkpp5d27v64y0hjep05" + }, + { + "amount": { + "amount": "190000000", + "denom": "bnb" + }, + "cdp_id": "401", + "depositor": "kava13jsjaj9mgu8ld9795udsmwtq2z6w880la8pjgk" + }, + { + "amount": { + "amount": "500000000", + "denom": "bnb" + }, + "cdp_id": "402", + "depositor": "kava193zlfqknqhsxsvwerghyhaak57vqxc85c4an75" + }, + { + "amount": { + "amount": "9039810000", + "denom": "bnb" + }, + "cdp_id": "403", + "depositor": "kava1vc4jkya3ngzr8nm9g0pqjq245zyedtdns2wgjl" + }, + { + "amount": { + "amount": "80638992", + "denom": "bnb" + }, + "cdp_id": "404", + "depositor": "kava1wgsaae4xsxwxwt6tdzlrecfh4ryv7pgg8sq62c" + }, + { + "amount": { + "amount": "2000000000", + "denom": "bnb" + }, + "cdp_id": "405", + "depositor": "kava1346xxrjlgks6k4985h56h8nz4g00ywx9sy2fmx" + }, + { + "amount": { + "amount": "15639560000", + "denom": "bnb" + }, + "cdp_id": "407", + "depositor": "kava1fj8454k6sm4rjr78u45ls6xyc2hwpt9qmcx70d" + }, + { + "amount": { + "amount": "1539999000", + "denom": "bnb" + }, + "cdp_id": "408", + "depositor": "kava1l8txdnmj888kr9xjzyqrcpwns8wvser6wq63q0" + }, + { + "amount": { + "amount": "300000000", + "denom": "bnb" + }, + "cdp_id": "410", + "depositor": "kava1tpwv2a3uqg44axz0wue20ym6wzu2ku256q4wwy" + }, + { + "amount": { + "amount": "1033961500", + "denom": "bnb" + }, + "cdp_id": "411", + "depositor": "kava1ajxngqkmc05js4m7v54sv3z0ajxn2rxx20vecm" + }, + { + "amount": { + "amount": "500000000", + "denom": "bnb" + }, + "cdp_id": "412", + "depositor": "kava18dh0mkakhgfp434vnpfl3cumd8ezgj7d8d5thj" + }, + { + "amount": { + "amount": "338627511", + "denom": "bnb" + }, + "cdp_id": "413", + "depositor": "kava18smvkrmxz6hz9ue9x37jke3ygkmzsmfvcq7wsk" + }, + { + "amount": { + "amount": "116220000", + "denom": "bnb" + }, + "cdp_id": "414", + "depositor": "kava1scecy0k0d7rda0muu0cgy693fwl39zdsh2jsts" + }, + { + "amount": { + "amount": "364186300", + "denom": "bnb" + }, + "cdp_id": "415", + "depositor": "kava1yjy9vjm7p6cwtcefm7haf0czawrz0x8tajswt4" + }, + { + "amount": { + "amount": "2933574070", + "denom": "bnb" + }, + "cdp_id": "417", + "depositor": "kava19kncpd7la86z27snj6996u3ds5mtcmc5n864vx" + }, + { + "amount": { + "amount": "52289147", + "denom": "bnb" + }, + "cdp_id": "418", + "depositor": "kava1vdnqddartdwjexhddpmxtv5exc74gnsk56qp48" + }, + { + "amount": { + "amount": "11225766569", + "denom": "bnb" + }, + "cdp_id": "419", + "depositor": "kava184jc94y8canrz64cqwa8qpfgtjfkgasng4lfkc" + }, + { + "amount": { + "amount": "2190150087", + "denom": "bnb" + }, + "cdp_id": "420", + "depositor": "kava1cxemt79nuwgsmx6lem49dk2l4tpqgtnzngvsw8" + }, + { + "amount": { + "amount": "25190971629", + "denom": "bnb" + }, + "cdp_id": "421", + "depositor": "kava1hrgp4sumhxcav5gs3xepa9h2pxg0lm74af88pa" + }, + { + "amount": { + "amount": "4349761500", + "denom": "bnb" + }, + "cdp_id": "422", + "depositor": "kava1n7tqawsk5fsc85cx74s96f9gpvhjklmp2rd35t" + }, + { + "amount": { + "amount": "23999999000", + "denom": "bnb" + }, + "cdp_id": "424", + "depositor": "kava1jr68259ur9fk0rpsjqgdc2yu92ktxjznkhkzkp" + }, + { + "amount": { + "amount": "999861500", + "denom": "bnb" + }, + "cdp_id": "426", + "depositor": "kava1gqgnuyzz5w03wjul2cmsk4lgh7ysz300rtyqv2" + }, + { + "amount": { + "amount": "650000000", + "denom": "bnb" + }, + "cdp_id": "428", + "depositor": "kava15njsc4lap2h94xum2xatf9xmex4088u9wd0u6z" + }, + { + "amount": { + "amount": "58000000", + "denom": "bnb" + }, + "cdp_id": "429", + "depositor": "kava1pqdfq0c8ul2ud570fkgurv0e0kkyun4njcu908" + }, + { + "amount": { + "amount": "420000000", + "denom": "bnb" + }, + "cdp_id": "430", + "depositor": "kava1k3njlxztcptmr8g9s3hasw9r6ljje3z2jmg5e0" + }, + { + "amount": { + "amount": "101138000", + "denom": "bnb" + }, + "cdp_id": "431", + "depositor": "kava1mkqjs4q5udknncq0804npdl6ft0955faf6dlkw" + }, + { + "amount": { + "amount": "98924250", + "denom": "bnb" + }, + "cdp_id": "432", + "depositor": "kava14n3j3lk8qv9l7qaezhk9tvxaxxenv8fe5ljkjq" + }, + { + "amount": { + "amount": "110109408500", + "denom": "bnb" + }, + "cdp_id": "435", + "depositor": "kava1egg63hrypuyt2lt9a4n5djd9pm6map27rwwfze" + }, + { + "amount": { + "amount": "208961500", + "denom": "bnb" + }, + "cdp_id": "436", + "depositor": "kava1gtk0jkrhkah3v89tyl4uju9pfxaqf6x7k37jx2" + }, + { + "amount": { + "amount": "800000000", + "denom": "bnb" + }, + "cdp_id": "437", + "depositor": "kava1uywh7xykpca22jqwpx2y04a6gvf8xkc7slggrj" + }, + { + "amount": { + "amount": "100000000", + "denom": "bnb" + }, + "cdp_id": "438", + "depositor": "kava18khx7upj3m2wx5csg974saseneg0yhdljz58e4" + }, + { + "amount": { + "amount": "199999000", + "denom": "bnb" + }, + "cdp_id": "440", + "depositor": "kava1ljfxurrts4m0prurlvgvmu9y5yxmf9s0tewuyw" + }, + { + "amount": { + "amount": "749980750", + "denom": "bnb" + }, + "cdp_id": "441", + "depositor": "kava1zzz79tppy6ymqh6cqcs9sghjmfc8l2sex36yhy" + }, + { + "amount": { + "amount": "377999000", + "denom": "bnb" + }, + "cdp_id": "442", + "depositor": "kava1p6ukkxqy46dv88cw5cwruj3e26cywq4w8wdw57" + }, + { + "amount": { + "amount": "107369000", + "denom": "bnb" + }, + "cdp_id": "443", + "depositor": "kava1gv4w4epka7hk9yrhjg36952hjpvxl66xk5tunc" + }, + { + "amount": { + "amount": "201180000", + "denom": "bnb" + }, + "cdp_id": "444", + "depositor": "kava1tqzyvc705vxc7wxzkvaj4h4kmy0laqltkr4ccu" + }, + { + "amount": { + "amount": "5642037815", + "denom": "bnb" + }, + "cdp_id": "445", + "depositor": "kava1sy2gskxervkfv7ug33e78ty7hmg579w3n67gnr" + }, + { + "amount": { + "amount": "46124894121", + "denom": "bnb" + }, + "cdp_id": "448", + "depositor": "kava175nsnv7cgf23zczudp62avveqdstkaenlhmdkv" + }, + { + "amount": { + "amount": "520207013074", + "denom": "bnb" + }, + "cdp_id": "449", + "depositor": "kava15w26ypf03ew40s2rlpvz6w6zewjllux2nd9zh6" + }, + { + "amount": { + "amount": "119119000", + "denom": "bnb" + }, + "cdp_id": "450", + "depositor": "kava1yc7r3qfqxlds6aw6p9egy42vn8n8wu5hd0ksvm" + }, + { + "amount": { + "amount": "2696108986", + "denom": "bnb" + }, + "cdp_id": "453", + "depositor": "kava1egckau5qukmpuvkz9f8e8dk3z47jc3tz5xhfnn" + }, + { + "amount": { + "amount": "5199999000", + "denom": "bnb" + }, + "cdp_id": "455", + "depositor": "kava1p5j4vfecg4afhvy04lc43kr8xwe3lg8awpr6tu" + }, + { + "amount": { + "amount": "94567858", + "denom": "bnb" + }, + "cdp_id": "456", + "depositor": "kava10l4pyd0u4k4lrjkuykepkek9r6rnsmw96w70cv" + }, + { + "amount": { + "amount": "280000000", + "denom": "bnb" + }, + "cdp_id": "457", + "depositor": "kava1ggcxyngdy2zk5ef3spxkyk0lavfxx4yhvx50gp" + }, + { + "amount": { + "amount": "84746000", + "denom": "bnb" + }, + "cdp_id": "458", + "depositor": "kava1vcrz5geulv3gywlmv22vvdd57dgxwu9qtq2wv7" + }, + { + "amount": { + "amount": "99999000", + "denom": "bnb" + }, + "cdp_id": "459", + "depositor": "kava1kfm0ap7dj70g84tnm6t7sv9e07alv40sswlp26" + }, + { + "amount": { + "amount": "599999000", + "denom": "bnb" + }, + "cdp_id": "460", + "depositor": "kava1qhjahz8wcd2v45vhqguftxzdcmevmqult0cr6q" + }, + { + "amount": { + "amount": "161916690", + "denom": "bnb" + }, + "cdp_id": "461", + "depositor": "kava14me2jfmcxrvt0wc3yrthaa0wyajunjuvdhqdgw" + }, + { + "amount": { + "amount": "600000000", + "denom": "bnb" + }, + "cdp_id": "462", + "depositor": "kava1r6863cfuphfqn9e8csrh5nwt478hqys0m55jev" + }, + { + "amount": { + "amount": "278673000", + "denom": "bnb" + }, + "cdp_id": "464", + "depositor": "kava1q9f35kmf3nmkh8njf504wa9f8xlf5xk730hyaw" + }, + { + "amount": { + "amount": "75545000", + "denom": "bnb" + }, + "cdp_id": "465", + "depositor": "kava1hj482tmy0tgmtvu75t9j0plmaqn2xm0vy5v6r2" + }, + { + "amount": { + "amount": "708603424", + "denom": "bnb" + }, + "cdp_id": "467", + "depositor": "kava1h664863rtt9hs2ty2vrdslvsa4s253zt08vkjk" + }, + { + "amount": { + "amount": "399908995", + "denom": "bnb" + }, + "cdp_id": "469", + "depositor": "kava18ctftdnzf5npek5lgjsdnv89yzgmcur5vmm4kt" + }, + { + "amount": { + "amount": "200000000", + "denom": "bnb" + }, + "cdp_id": "470", + "depositor": "kava1v5amsvjqkj9jhgt524qfwzkgqpppxrjwhqxsn5" + }, + { + "amount": { + "amount": "111855575", + "denom": "bnb" + }, + "cdp_id": "472", + "depositor": "kava1czsgyezfdngjncz722fd5h7erpk6rg9hxr46kv" + }, + { + "amount": { + "amount": "503345144", + "denom": "bnb" + }, + "cdp_id": "473", + "depositor": "kava17a9ac5ehxuaskms96pht653xc8n8geyln5t04g" + }, + { + "amount": { + "amount": "160000000", + "denom": "bnb" + }, + "cdp_id": "474", + "depositor": "kava1jyackhsdvgltkwuanh86zj2eyctyqxpfp5jlpz" + }, + { + "amount": { + "amount": "5405751556", + "denom": "bnb" + }, + "cdp_id": "475", + "depositor": "kava1yzy4ynjw3047m3pn0kmawc3hrwq0tk5aggurf6" + }, + { + "amount": { + "amount": "99810345", + "denom": "bnb" + }, + "cdp_id": "476", + "depositor": "kava152jmxqetd54qy0twfw986xmqc8z55e8lek6jln" + }, + { + "amount": { + "amount": "900000000", + "denom": "bnb" + }, + "cdp_id": "477", + "depositor": "kava1munszk8x4te0h94wag7qfqa02hzk5c9jy25qlr" + }, + { + "amount": { + "amount": "2055177425", + "denom": "bnb" + }, + "cdp_id": "479", + "depositor": "kava1qs9h8xtdvdzxr9xn0d43f6xmp8z0af4l3kxu2n" + }, + { + "amount": { + "amount": "2118498000", + "denom": "bnb" + }, + "cdp_id": "480", + "depositor": "kava10fm5uqusl69y7tz0lzzwa28u0aht0keshyyxr4" + }, + { + "amount": { + "amount": "377334585500", + "denom": "bnb" + }, + "cdp_id": "481", + "depositor": "kava1v24lr93py37rgqf8nf99nay3letx5dtv4jnpn4" + }, + { + "amount": { + "amount": "249999000", + "denom": "bnb" + }, + "cdp_id": "482", + "depositor": "kava19h4c5a5ma0ldhwynzgnefvjx8003532y3llnuq" + }, + { + "amount": { + "amount": "48809998001", + "denom": "bnb" + }, + "cdp_id": "483", + "depositor": "kava1qvsus5qg8yhre7k2c78xkkw4nvqqgev7ezrja8" + }, + { + "amount": { + "amount": "2399997000", + "denom": "bnb" + }, + "cdp_id": "484", + "depositor": "kava104v3e5ydyszf6t0k5hsgcqw2hhpvekvj8xdu4p" + }, + { + "amount": { + "amount": "72475070", + "denom": "bnb" + }, + "cdp_id": "485", + "depositor": "kava1xavpqv7s3thhlyn4t7n7mlfrgs52yyw50dyvj2" + }, + { + "amount": { + "amount": "99999000", + "denom": "bnb" + }, + "cdp_id": "486", + "depositor": "kava1cmw28jgmz678srf67u58kvtcqfqe96xhz4utu6" + }, + { + "amount": { + "amount": "4311353945", + "denom": "bnb" + }, + "cdp_id": "487", + "depositor": "kava1w6wpqtr33cqqspwff6wjrn3ppx083upn383fr4" + }, + { + "amount": { + "amount": "73130540", + "denom": "bnb" + }, + "cdp_id": "489", + "depositor": "kava1tuldyjrm4njrzqhcqr9dwc49n6qmmy3yf7rwm9" + }, + { + "amount": { + "amount": "399961500", + "denom": "bnb" + }, + "cdp_id": "490", + "depositor": "kava1lyhy6urjpcw7j39ms5zsdjfc8ceks0rtketuu7" + }, + { + "amount": { + "amount": "535399999000", + "denom": "bnb" + }, + "cdp_id": "493", + "depositor": "kava1f987vmkptm4erfr4pkxz7em2dqv9levu788n3s" + }, + { + "amount": { + "amount": "100097000", + "denom": "bnb" + }, + "cdp_id": "494", + "depositor": "kava16exxhy0llf80mke2kue7rpvd0tydzel67mr5gz" + }, + { + "amount": { + "amount": "350000000", + "denom": "bnb" + }, + "cdp_id": "495", + "depositor": "kava1ksdwmtj2kvn3ca3p7acmr7a7ke5vf3r3vallqy" + }, + { + "amount": { + "amount": "138431097", + "denom": "bnb" + }, + "cdp_id": "497", + "depositor": "kava16nkl3flcdm26hsza5q8zlgqpqtntems6ua0yxh" + }, + { + "amount": { + "amount": "229948554", + "denom": "bnb" + }, + "cdp_id": "500", + "depositor": "kava1afjd6f4ucljlsqd8srkhcph6h9su9xr28gnlej" + }, + { + "amount": { + "amount": "204788332", + "denom": "bnb" + }, + "cdp_id": "503", + "depositor": "kava1pzsjduk42le33zyjrlch7uged7f8n5zcaf2kdv" + }, + { + "amount": { + "amount": "143087090", + "denom": "bnb" + }, + "cdp_id": "506", + "depositor": "kava1q0pv87dmzwldqjvepd60xlny9q9xajd6x4sga5" + }, + { + "amount": { + "amount": "109861500", + "denom": "bnb" + }, + "cdp_id": "507", + "depositor": "kava1ve5h4gdygeh7cyssflpel6xht5hrzpw0yc9akj" + }, + { + "amount": { + "amount": "89961500", + "denom": "bnb" + }, + "cdp_id": "508", + "depositor": "kava17shza044el9zejk7hd5wqcm85sankrcr3pjshv" + }, + { + "amount": { + "amount": "5103611500", + "denom": "bnb" + }, + "cdp_id": "510", + "depositor": "kava1famggza0sju5964gls45pmz2662fluwst53xq3" + }, + { + "amount": { + "amount": "2965833131", + "denom": "bnb" + }, + "cdp_id": "511", + "depositor": "kava164t922sdhpchajlvydywt3wdsd0tt3k5zp9lql" + }, + { + "amount": { + "amount": "1162399471000", + "denom": "bnb" + }, + "cdp_id": "512", + "depositor": "kava15fu6ehw756hd3dyvws0xfwmrugfz8m6f5n030l" + }, + { + "amount": { + "amount": "100706134", + "denom": "bnb" + }, + "cdp_id": "513", + "depositor": "kava1jgh5t0nmuhq4ujay6wtth7yzpdvzqqsqdue8s7" + }, + { + "amount": { + "amount": "15203754344", + "denom": "bnb" + }, + "cdp_id": "514", + "depositor": "kava1arvsc39ytsu7tx8fhtx2c9l2naqgzhgwpce2zj" + }, + { + "amount": { + "amount": "99920000", + "denom": "bnb" + }, + "cdp_id": "518", + "depositor": "kava1fffdmzjvzvem2v9ac4a223uc477rev77r5yypg" + }, + { + "amount": { + "amount": "199961500", + "denom": "bnb" + }, + "cdp_id": "527", + "depositor": "kava14fnf4afrj60tcv4gc2w5jvhfyq6dered64c7g4" + }, + { + "amount": { + "amount": "10222401459", + "denom": "bnb" + }, + "cdp_id": "529", + "depositor": "kava1f2q535jw6z4c590apll5j77kdm7ka0qzwksvru" + }, + { + "amount": { + "amount": "4211962937", + "denom": "bnb" + }, + "cdp_id": "530", + "depositor": "kava1utp56q3kn8e8yn0ndsw8n6wef2yqg5umtuywy8" + }, + { + "amount": { + "amount": "152894876", + "denom": "bnb" + }, + "cdp_id": "532", + "depositor": "kava1gyynypgz03qq9jdf0u7y3w8uuw9ey3lksjn0nc" + }, + { + "amount": { + "amount": "1544009070", + "denom": "bnb" + }, + "cdp_id": "534", + "depositor": "kava1u84mr5ndzx29q0pxvv9zyqq0wcth780hycrt0m" + }, + { + "amount": { + "amount": "89999723000", + "denom": "bnb" + }, + "cdp_id": "537", + "depositor": "kava1pmkn0rn07yqcfq0x2za5s3hvecufve3qttwfmw" + }, + { + "amount": { + "amount": "248701778", + "denom": "bnb" + }, + "cdp_id": "538", + "depositor": "kava1fzemz4j2tzrxah9r9fpdecdz46f04mlkhaj3fw" + }, + { + "amount": { + "amount": "200000000", + "denom": "bnb" + }, + "cdp_id": "539", + "depositor": "kava1s0sng9l2espfdu49a25d4r0ewjd0qjkj42jm49" + }, + { + "amount": { + "amount": "99999000", + "denom": "bnb" + }, + "cdp_id": "541", + "depositor": "kava120jyzpzu8ugg697zg7z5a4epfh0dxt44xtx930" + }, + { + "amount": { + "amount": "149584500", + "denom": "bnb" + }, + "cdp_id": "542", + "depositor": "kava1p9zta57w420jqh6y24az869nufzzcf25a3w6w3" + }, + { + "amount": { + "amount": "82740000", + "denom": "bnb" + }, + "cdp_id": "544", + "depositor": "kava1pd79wry4m8xqcr8nu66uz0j9qxkh6v7af9w9yx" + }, + { + "amount": { + "amount": "362447000", + "denom": "bnb" + }, + "cdp_id": "545", + "depositor": "kava1kt4ss0ewq2u0yuqlmqx2ky3f5a96sj4adzpghp" + }, + { + "amount": { + "amount": "9973286751", + "denom": "bnb" + }, + "cdp_id": "546", + "depositor": "kava155wzd5qzxs2wc58gw2czxy57k6cf6lpl4dphha" + }, + { + "amount": { + "amount": "3412923000", + "denom": "bnb" + }, + "cdp_id": "548", + "depositor": "kava17j57lk8cx7ndfyekfm6t0aeva2zpsj2scrct9c" + }, + { + "amount": { + "amount": "74136275", + "denom": "bnb" + }, + "cdp_id": "549", + "depositor": "kava1gl0y28ghee428e38ca9y3ges7dw3w6akfldpf2" + }, + { + "amount": { + "amount": "210947990", + "denom": "bnb" + }, + "cdp_id": "550", + "depositor": "kava1agd0k03g4qd6khel3greh9rpfvpwnwnpwwe7nd" + }, + { + "amount": { + "amount": "99999000", + "denom": "bnb" + }, + "cdp_id": "553", + "depositor": "kava14pczfzuxj2x5waf7havqh3uzk65psye56u9tpw" + }, + { + "amount": { + "amount": "109484500", + "denom": "bnb" + }, + "cdp_id": "554", + "depositor": "kava1q2tzz7g67jkfr40qsmrd3mlc0rcnasc2v5yyqa" + }, + { + "amount": { + "amount": "399908995", + "denom": "bnb" + }, + "cdp_id": "559", + "depositor": "kava1ws3z8cd6zy4sty6m3wezd56v53swr8fpzjs96u" + }, + { + "amount": { + "amount": "649248043", + "denom": "bnb" + }, + "cdp_id": "561", + "depositor": "kava17ltd0q3277h2w6wplqsfxe2l3hj30jaeqg3nf0" + }, + { + "amount": { + "amount": "1999884500", + "denom": "bnb" + }, + "cdp_id": "562", + "depositor": "kava10lhnlwlek6yg5n734jn8qukur2kjjhcw09xagl" + }, + { + "amount": { + "amount": "99961500", + "denom": "bnb" + }, + "cdp_id": "564", + "depositor": "kava1dkv7dt5dus66v3qssk3xvejlspqcyjtam5822s" + }, + { + "amount": { + "amount": "199999000", + "denom": "bnb" + }, + "cdp_id": "565", + "depositor": "kava1wk3cra4t0ma7fmd0lzwt4v0r2zmuw5dac4dgj8" + }, + { + "amount": { + "amount": "199861500", + "denom": "bnb" + }, + "cdp_id": "567", + "depositor": "kava1uyhegc7h4mdc688jrkkqpr3p7wfuwk5kjmqr3q" + }, + { + "amount": { + "amount": "100000000", + "denom": "bnb" + }, + "cdp_id": "570", + "depositor": "kava1a55mtutup4gsefhlgl2eyquqvddhcthajj7hyl" + }, + { + "amount": { + "amount": "101950000", + "denom": "bnb" + }, + "cdp_id": "571", + "depositor": "kava1d75drw4t90c8u4cpnrj5skt9dptd8ndq5pfnfg" + }, + { + "amount": { + "amount": "140000000", + "denom": "bnb" + }, + "cdp_id": "573", + "depositor": "kava1jy5s2j6m9qe5ctyu528fa527s88xt7vmvlvn9h" + }, + { + "amount": { + "amount": "94108000", + "denom": "bnb" + }, + "cdp_id": "577", + "depositor": "kava1lqgw9gczxfrnlyqj3wxcjpe72xlwka8l707t07" + }, + { + "amount": { + "amount": "24999900000000", + "denom": "bnb" + }, + "cdp_id": "584", + "depositor": "kava1p3ucd3ptpw902fluyjzhq3ffgq4ntddaysyq8h" + }, + { + "amount": { + "amount": "1268288000", + "denom": "bnb" + }, + "cdp_id": "585", + "depositor": "kava1ym6mnfu60ss26jxe3q4uu3r9q6mm9jhvsd6v42" + }, + { + "amount": { + "amount": "100000000", + "denom": "bnb" + }, + "cdp_id": "586", + "depositor": "kava1fr7z092tv959sv6ktnqp6hf0gewcepn6rjere7" + }, + { + "amount": { + "amount": "519000000", + "denom": "bnb" + }, + "cdp_id": "588", + "depositor": "kava1m9fdeu7d96ea6w925cj84573fz9czx0juuj3yk" + }, + { + "amount": { + "amount": "112019000", + "denom": "bnb" + }, + "cdp_id": "590", + "depositor": "kava1ph2cglswrvle0yynw8klqvc9xq2g0c79km4vj8" + }, + { + "amount": { + "amount": "31021777858", + "denom": "bnb" + }, + "cdp_id": "591", + "depositor": "kava1tk26wrslz7kn297uhgavhu4wuqqh63ypueww8e" + }, + { + "amount": { + "amount": "711579883", + "denom": "bnb" + }, + "cdp_id": "593", + "depositor": "kava1x3ppp8k0d3r70wmzk8sjjcwsh7m8lwpskympuq" + }, + { + "amount": { + "amount": "90000000", + "denom": "bnb" + }, + "cdp_id": "595", + "depositor": "kava1heexugcm6rvxrdhefhesu9z7xfgwpv5p0vdnxq" + }, + { + "amount": { + "amount": "293947000", + "denom": "bnb" + }, + "cdp_id": "598", + "depositor": "kava1rgh7rscdgr24ezzdq8qmcqr4ztkye9mz8am7jn" + }, + { + "amount": { + "amount": "108507500", + "denom": "bnb" + }, + "cdp_id": "599", + "depositor": "kava1l820ssg03trajf9m90a7ftf8wj4au80f9ysx6j" + }, + { + "amount": { + "amount": "1092945394", + "denom": "bnb" + }, + "cdp_id": "600", + "depositor": "kava183qwnf0k69pt685whvz7pf2aqlc74dks73rljc" + }, + { + "amount": { + "amount": "187656122", + "denom": "bnb" + }, + "cdp_id": "601", + "depositor": "kava1t2zha9k5ghuw3s03dm4h80u5m0nkrln4mzk45e" + }, + { + "amount": { + "amount": "100000000", + "denom": "bnb" + }, + "cdp_id": "603", + "depositor": "kava1lpu4p4wxxqk60awyfsd6wc382kpf87l52n7kan" + }, + { + "amount": { + "amount": "2298136499", + "denom": "bnb" + }, + "cdp_id": "604", + "depositor": "kava144ufawnvyjpfpw9cf65jj35jhun7qzl948fw7v" + }, + { + "amount": { + "amount": "100000000", + "denom": "bnb" + }, + "cdp_id": "606", + "depositor": "kava1c2y4xkxrly9jj7nj5pklukuegenhzyar5l8umf" + }, + { + "amount": { + "amount": "99861500", + "denom": "bnb" + }, + "cdp_id": "608", + "depositor": "kava1qahvnv9yypfn3d2jmur3fpz8y6qhw9hvkzespj" + }, + { + "amount": { + "amount": "10000000000", + "denom": "bnb" + }, + "cdp_id": "609", + "depositor": "kava1u0keta2qcwd4m6wn48j80nwrsck3d8e9sfzk2w" + }, + { + "amount": { + "amount": "89840000", + "denom": "bnb" + }, + "cdp_id": "611", + "depositor": "kava1nmc03lhn9mmazle9rt9dpctrrk7ld3p6pn0sml" + }, + { + "amount": { + "amount": "509925634", + "denom": "bnb" + }, + "cdp_id": "613", + "depositor": "kava14s6qe2efrxnn686jztajqgauey0wekr3f4vmnt" + }, + { + "amount": { + "amount": "3030585962", + "denom": "bnb" + }, + "cdp_id": "614", + "depositor": "kava1rpmcujjl23d5drt43kssx8m3cdpv2rgssy98cn" + }, + { + "amount": { + "amount": "26776990500", + "denom": "bnb" + }, + "cdp_id": "615", + "depositor": "kava1y0rytym5j70wl9cdh39e4myclgdhsctvp8mh7e" + }, + { + "amount": { + "amount": "2219861500", + "denom": "bnb" + }, + "cdp_id": "616", + "depositor": "kava197qyvn22tet77z5mk78ck95g9wmtq3lckrgfzq" + }, + { + "amount": { + "amount": "62314233", + "denom": "bnb" + }, + "cdp_id": "618", + "depositor": "kava1757dx4vjqa7f9tqtvwp3qm4rhwe7rutdz0fup0" + }, + { + "amount": { + "amount": "338840360", + "denom": "bnb" + }, + "cdp_id": "620", + "depositor": "kava198z78dq8pgrclfuexjxuxju2evcvg6qvpsftpx" + }, + { + "amount": { + "amount": "10016683837", + "denom": "bnb" + }, + "cdp_id": "622", + "depositor": "kava19zqpv4s3hm9wa7t3kwsefj56xfu5477mln2gr5" + }, + { + "amount": { + "amount": "553291747747", + "denom": "bnb" + }, + "cdp_id": "624", + "depositor": "kava1ldyc7pkjtcy9gd8lul653s40mtalp8904hzt86" + }, + { + "amount": { + "amount": "2299998000", + "denom": "bnb" + }, + "cdp_id": "627", + "depositor": "kava1ce2d3qlhyw0zymvcmnrpdgt8nlfmt3zxw460yl" + }, + { + "amount": { + "amount": "5000000000", + "denom": "bnb" + }, + "cdp_id": "631", + "depositor": "kava1hw5j9p9mqtye42rvjqggkxs283spjtx9ns5tnk" + }, + { + "amount": { + "amount": "149859500", + "denom": "bnb" + }, + "cdp_id": "632", + "depositor": "kava1vu905f0043mq5wdry0q8gvlpvu8h4hx4894d76" + }, + { + "amount": { + "amount": "998808462", + "denom": "bnb" + }, + "cdp_id": "634", + "depositor": "kava15nffgda7t668av06vhqz3ypks94gas9kla36aa" + }, + { + "amount": { + "amount": "149824000", + "denom": "bnb" + }, + "cdp_id": "636", + "depositor": "kava1pckx96w35njptwnel9j2eg3ac52ruemepslxcj" + }, + { + "amount": { + "amount": "568858706", + "denom": "bnb" + }, + "cdp_id": "637", + "depositor": "kava1245ydegvlzp0rr3q5a0ejwyr0e2zaejtuv34rj" + }, + { + "amount": { + "amount": "90000000", + "denom": "bnb" + }, + "cdp_id": "638", + "depositor": "kava1fnsu4x447vqr36lf733x8xyem3ulvktg54gsar" + }, + { + "amount": { + "amount": "4999000000", + "denom": "bnb" + }, + "cdp_id": "639", + "depositor": "kava19cagyd5nu3xalnxlwh29fs9qnwfgv2jc8m4cwd" + }, + { + "amount": { + "amount": "227828700", + "denom": "bnb" + }, + "cdp_id": "640", + "depositor": "kava10fsu58fz5p3pny66t7lx4t07x0aeahgc7dkz0k" + }, + { + "amount": { + "amount": "2499961500", + "denom": "bnb" + }, + "cdp_id": "641", + "depositor": "kava1dt4dsl6tmwa286gaua3edhe2hx8y7f6yag0ycc" + }, + { + "amount": { + "amount": "1099823000", + "denom": "bnb" + }, + "cdp_id": "644", + "depositor": "kava1tgwt0fs7ewk5en5f4l0lta96je67qzszs6a9av" + }, + { + "amount": { + "amount": "120094116321", + "denom": "bnb" + }, + "cdp_id": "645", + "depositor": "kava1060g6qppa3pr079s9skd7h2vzzjshdyd6u93kt" + }, + { + "amount": { + "amount": "70204605500", + "denom": "bnb" + }, + "cdp_id": "647", + "depositor": "kava19mtegk4rd6fjfxjsmknn8862gcmfd32myj7sva" + }, + { + "amount": { + "amount": "599646000", + "denom": "bnb" + }, + "cdp_id": "648", + "depositor": "kava1t7t6fweerd5azv0rdjqggylg6zj08u5thp2uz4" + }, + { + "amount": { + "amount": "116615233", + "denom": "bnb" + }, + "cdp_id": "649", + "depositor": "kava1wghqx6uq2gr7medxc9s8rsvy39720ecneyren3" + }, + { + "amount": { + "amount": "999684500", + "denom": "bnb" + }, + "cdp_id": "650", + "depositor": "kava15vkeet287q7g379zhjdgp3ljz0x0lsz0glqan7" + }, + { + "amount": { + "amount": "706776294", + "denom": "bnb" + }, + "cdp_id": "651", + "depositor": "kava1etc48067kxc29k0n86pwl3l92vp8fszvsevcm7" + }, + { + "amount": { + "amount": "117406278", + "denom": "bnb" + }, + "cdp_id": "654", + "depositor": "kava1ufhu8zlswufcvu82kqeu0jgclum2psvx453f4p" + }, + { + "amount": { + "amount": "599000000", + "denom": "bnb" + }, + "cdp_id": "657", + "depositor": "kava1yhp6n6wdf7xevyn2r2z85m0ejrgl3rfe9akmnv" + }, + { + "amount": { + "amount": "137999584500", + "denom": "bnb" + }, + "cdp_id": "659", + "depositor": "kava1pu9g0q0ceduaq0827l0pkyjgejcfn66zg9n0rq" + }, + { + "amount": { + "amount": "1009999000", + "denom": "bnb" + }, + "cdp_id": "663", + "depositor": "kava19t5f34y3m4cy983gdzgm02yjax8utyqy7aexp9" + }, + { + "amount": { + "amount": "90157124", + "denom": "bnb" + }, + "cdp_id": "665", + "depositor": "kava1fzzfexc5zzqgpt9jm4vvhuhagvg0m36z2gldl3" + }, + { + "amount": { + "amount": "179860500", + "denom": "bnb" + }, + "cdp_id": "666", + "depositor": "kava1wlzmzdhyyw82ea484lnx4yjrahxstrnrxxxr84" + }, + { + "amount": { + "amount": "159104617", + "denom": "bnb" + }, + "cdp_id": "667", + "depositor": "kava1nzqt43xzltcnj0ylwn6k5q6d99efhl60l2z5f5" + }, + { + "amount": { + "amount": "99999997000", + "denom": "bnb" + }, + "cdp_id": "670", + "depositor": "kava10ay55dxkrlhy9vdaj6pr9zexwalp6cjtauepvl" + }, + { + "amount": { + "amount": "3500000000", + "denom": "bnb" + }, + "cdp_id": "672", + "depositor": "kava16lhwsqujy9tqv38k3d2jwyuqupj7rtwrxwk668" + }, + { + "amount": { + "amount": "140050000", + "denom": "bnb" + }, + "cdp_id": "673", + "depositor": "kava14xkem8rgndu4ptkt7p398c8ujrqgzg9regxcj9" + }, + { + "amount": { + "amount": "88345156", + "denom": "bnb" + }, + "cdp_id": "674", + "depositor": "kava19eqckwrd77ec0nq64r2c7nzrxvekmd5el7l7x0" + }, + { + "amount": { + "amount": "103340000", + "denom": "bnb" + }, + "cdp_id": "675", + "depositor": "kava1d3uwmaelq8guzryhkttmsjsu676ykw26l2cdzu" + }, + { + "amount": { + "amount": "2495718637", + "denom": "bnb" + }, + "cdp_id": "679", + "depositor": "kava15784n673568qcxc2m9eylnuzdhmnf7jau0hdxk" + }, + { + "amount": { + "amount": "84994651", + "denom": "bnb" + }, + "cdp_id": "683", + "depositor": "kava129h49z4glgh6lrpl5amj9terauw0m2qgmrz0us" + }, + { + "amount": { + "amount": "152055509", + "denom": "bnb" + }, + "cdp_id": "684", + "depositor": "kava1w4umquan7w2v3n3enh6ap854vk4a58kftnq4au" + }, + { + "amount": { + "amount": "5940861500", + "denom": "bnb" + }, + "cdp_id": "685", + "depositor": "kava1tusm6xvctqahxcwdl3q3v50mw0dnecf6frt6ve" + }, + { + "amount": { + "amount": "27199856500", + "denom": "bnb" + }, + "cdp_id": "688", + "depositor": "kava1mwpvqkvyxgf60pqwvr2vxq0yy86f3kqzcpqarr" + }, + { + "amount": { + "amount": "950000000", + "denom": "bnb" + }, + "cdp_id": "690", + "depositor": "kava1fnrfp3clq57pnsa5k2s0k3uxa8ap44sxj43hqh" + }, + { + "amount": { + "amount": "102785791", + "denom": "bnb" + }, + "cdp_id": "692", + "depositor": "kava1ys2eh89ym4gws20z5tyw28a6jufzwwn5dr6x6z" + }, + { + "amount": { + "amount": "69240000", + "denom": "bnb" + }, + "cdp_id": "695", + "depositor": "kava19w6akrjw4zaeyhnqxaucwyp4mgzffmqfxwelp9" + }, + { + "amount": { + "amount": "65060000", + "denom": "bnb" + }, + "cdp_id": "696", + "depositor": "kava1hzmc908kc2a8nmlgrlun4v8742vxmdx9gpz7d3" + }, + { + "amount": { + "amount": "2000000000", + "denom": "bnb" + }, + "cdp_id": "699", + "depositor": "kava1mx9kvdhwkp8r6qdh7kvj7j640ktg03a9qx26pk" + }, + { + "amount": { + "amount": "1145187581", + "denom": "bnb" + }, + "cdp_id": "700", + "depositor": "kava1vxzg3hwck6hny22pd0j83pv7h7wddj4gmu492c" + }, + { + "amount": { + "amount": "1581306691", + "denom": "bnb" + }, + "cdp_id": "701", + "depositor": "kava126wg3hfgrxspmtupvyqvall5g75xr7fmxdssen" + }, + { + "amount": { + "amount": "35000116000", + "denom": "bnb" + }, + "cdp_id": "702", + "depositor": "kava1kfrjwuur93wthdwc6kpf36lwftdzz22wxe5gae" + }, + { + "amount": { + "amount": "73000000", + "denom": "bnb" + }, + "cdp_id": "704", + "depositor": "kava1mgqnw8kwpclxle6n4cc64d5y2k3ma5gqumd9qz" + }, + { + "amount": { + "amount": "71134712", + "denom": "bnb" + }, + "cdp_id": "707", + "depositor": "kava188hqscan94ev9v8l0szekcmuz30gfrc4dcj57v" + }, + { + "amount": { + "amount": "100000000", + "denom": "bnb" + }, + "cdp_id": "708", + "depositor": "kava1cwwhp433awcth3906j8ljnk0a4986vs4n0ycjn" + }, + { + "amount": { + "amount": "131630000", + "denom": "bnb" + }, + "cdp_id": "711", + "depositor": "kava1vdm7qe7m0ml7lupghyqt94905fwksplwuztcwj" + }, + { + "amount": { + "amount": "227369000", + "denom": "bnb" + }, + "cdp_id": "714", + "depositor": "kava18u2vtjmcf4788cc3p5htp509zv0la4a3q8ahhd" + }, + { + "amount": { + "amount": "109996000", + "denom": "bnb" + }, + "cdp_id": "716", + "depositor": "kava1xnw3ty56drc6xyeuw4dl3pkj0sscasnmgfra45" + }, + { + "amount": { + "amount": "106112851", + "denom": "bnb" + }, + "cdp_id": "717", + "depositor": "kava1n0rncp6td9fss6nws05vc7tp7km8lqg26s2cup" + }, + { + "amount": { + "amount": "99150000", + "denom": "bnb" + }, + "cdp_id": "721", + "depositor": "kava1uct77gqud966lrvgm6mawelh4u6dl5ac0a33ve" + }, + { + "amount": { + "amount": "60000000", + "denom": "bnb" + }, + "cdp_id": "722", + "depositor": "kava1ssvlfv0l580ck33dfrpd9my2mkx72ur66h0zk7" + }, + { + "amount": { + "amount": "3615669408", + "denom": "bnb" + }, + "cdp_id": "723", + "depositor": "kava18crmeclf9lfjv5p56nw5pdwrmnl232u6z2p8r7" + }, + { + "amount": { + "amount": "2399999000", + "denom": "bnb" + }, + "cdp_id": "728", + "depositor": "kava1guwwcc8n9e7h66qzus93muh585ckj7qsdz5pfq" + }, + { + "amount": { + "amount": "129764000", + "denom": "bnb" + }, + "cdp_id": "733", + "depositor": "kava1gsn4670rqjcvym2p9dhw8euhl3w2ls7qyfkrpp" + }, + { + "amount": { + "amount": "525000000", + "denom": "bnb" + }, + "cdp_id": "734", + "depositor": "kava1p6mdwjhnd0v8vutx8238kndapp77nu66ky4gz5" + }, + { + "amount": { + "amount": "898457085", + "denom": "bnb" + }, + "cdp_id": "735", + "depositor": "kava1ttrw6gxz9nz49gse9v0tqqa2u97s34yx4shl55" + }, + { + "amount": { + "amount": "113729000", + "denom": "bnb" + }, + "cdp_id": "738", + "depositor": "kava1vlpsrmdyuywvaqrv7rx6xga224sqfwz3fyfhwq" + }, + { + "amount": { + "amount": "166401500", + "denom": "bnb" + }, + "cdp_id": "740", + "depositor": "kava1tvz5kalehzrmn0n3xvpeauvuvvcjar5vl23nny" + }, + { + "amount": { + "amount": "25061161959", + "denom": "bnb" + }, + "cdp_id": "741", + "depositor": "kava1up858ehlg5gsdfx068z42tmmjequky8cn5jzq3" + }, + { + "amount": { + "amount": "100000000", + "denom": "bnb" + }, + "cdp_id": "743", + "depositor": "kava16cxqgr30zvfktmupsk4yp4j6kkwmva2nj4rumh" + }, + { + "amount": { + "amount": "499999000", + "denom": "bnb" + }, + "cdp_id": "746", + "depositor": "kava1u7arfjp9pqhel7lpg2xlpm8yd3wsa7qdgvps47" + }, + { + "amount": { + "amount": "137739000", + "denom": "bnb" + }, + "cdp_id": "747", + "depositor": "kava1xyvekep7vx8lklmeframd67nsc2mvgajl56qd7" + }, + { + "amount": { + "amount": "2845998000", + "denom": "bnb" + }, + "cdp_id": "748", + "depositor": "kava1lynr3f7zqhpcwacvatewcwj0ar5q9sgx7tesj4" + }, + { + "amount": { + "amount": "93107606", + "denom": "bnb" + }, + "cdp_id": "751", + "depositor": "kava154ffftam7vp9u623fyag968qty4xdglj8nttqa" + }, + { + "amount": { + "amount": "86578132", + "denom": "bnb" + }, + "cdp_id": "752", + "depositor": "kava1mdzaz23a879hc33c8z9m5wqxyky060ylsqtxhp" + }, + { + "amount": { + "amount": "1480802919", + "denom": "bnb" + }, + "cdp_id": "756", + "depositor": "kava18d0er3p3esg4t0xq8nlsd568p2xh5l2rw864k0" + }, + { + "amount": { + "amount": "82061500", + "denom": "bnb" + }, + "cdp_id": "757", + "depositor": "kava1rmv7pfh2cn2vuzdxffq8ar8zjarjuaj05wfydq" + }, + { + "amount": { + "amount": "88651500", + "denom": "bnb" + }, + "cdp_id": "759", + "depositor": "kava1u87kxuwtcvzvfnmnv4xrxdz9e02uxw3vmu0rj0" + }, + { + "amount": { + "amount": "150000000", + "denom": "bnb" + }, + "cdp_id": "761", + "depositor": "kava1cfm868f9tyxuc8nhwht8uskdskcspukn2yhwfy" + }, + { + "amount": { + "amount": "1119961500", + "denom": "bnb" + }, + "cdp_id": "762", + "depositor": "kava1sqj3mx9ldpfdrl648gkgk97kt9vdgtpr8h54d4" + }, + { + "amount": { + "amount": "102329000", + "denom": "bnb" + }, + "cdp_id": "764", + "depositor": "kava1pswe4zg8agsn8vjqtp5y7p69c2uu9znc0jxmm6" + }, + { + "amount": { + "amount": "88169571", + "denom": "bnb" + }, + "cdp_id": "766", + "depositor": "kava1mmstl7fvtlgsp2n7kfrnww8ec83f0tmhvgc4cp" + }, + { + "amount": { + "amount": "2000000000", + "denom": "bnb" + }, + "cdp_id": "770", + "depositor": "kava18tmucr5zne0gl0qrflzj4j2p03vfrqqtmc7zu8" + }, + { + "amount": { + "amount": "25109997000", + "denom": "bnb" + }, + "cdp_id": "774", + "depositor": "kava1dkd54gp23afg7hlrczhpfr4rmgduqyfujgheg8" + }, + { + "amount": { + "amount": "1686459900", + "denom": "bnb" + }, + "cdp_id": "776", + "depositor": "kava1kyeqkawhfxjk34ce53lyx7z2akj495x3fe7nh2" + }, + { + "amount": { + "amount": "10000535500", + "denom": "bnb" + }, + "cdp_id": "777", + "depositor": "kava1delejz0pfradzear7rtx2gd5nvxyu97kvjhmuy" + }, + { + "amount": { + "amount": "98999000", + "denom": "bnb" + }, + "cdp_id": "778", + "depositor": "kava1rgtrf3nluqls6q3z6snyytzgtsf29d0eu4m4gu" + }, + { + "amount": { + "amount": "400061500", + "denom": "bnb" + }, + "cdp_id": "780", + "depositor": "kava1hzegeqztewllls8xldpeuje5xtnuehmdqjfa4n" + }, + { + "amount": { + "amount": "2422164173", + "denom": "bnb" + }, + "cdp_id": "781", + "depositor": "kava1pen6a6z7qwfjjuamtacgwcvyflcyncqv06sfkt" + }, + { + "amount": { + "amount": "3174124192", + "denom": "bnb" + }, + "cdp_id": "783", + "depositor": "kava17lx4arcck0settpt7ucfkjqg24qgx4jqwru68g" + }, + { + "amount": { + "amount": "92114872630", + "denom": "bnb" + }, + "cdp_id": "784", + "depositor": "kava1ghhk6fd4xtvxxu4v230x4acj27c2mkxe2tu7qm" + }, + { + "amount": { + "amount": "116823000", + "denom": "bnb" + }, + "cdp_id": "785", + "depositor": "kava1c7wnzssvtrpa02nvxqxnjcctv3fngncy9apy4h" + }, + { + "amount": { + "amount": "4431366591", + "denom": "bnb" + }, + "cdp_id": "788", + "depositor": "kava13vc2a42ea28d75tfuqmwykg7qxfrruzkdrwdug" + }, + { + "amount": { + "amount": "199997000", + "denom": "bnb" + }, + "cdp_id": "789", + "depositor": "kava1jqmsfadczrmtpeu3g68yuvq846hrplm3uchru8" + }, + { + "amount": { + "amount": "89148279", + "denom": "bnb" + }, + "cdp_id": "791", + "depositor": "kava15sndhqjegzpc32xyw9le0vv0d6n8r0jyvhq9u4" + }, + { + "amount": { + "amount": "499923000", + "denom": "bnb" + }, + "cdp_id": "792", + "depositor": "kava10pq9htfmwv35nsfke00tyfjsndqg5p09rzhtrf" + }, + { + "amount": { + "amount": "137934500", + "denom": "bnb" + }, + "cdp_id": "794", + "depositor": "kava15m89rn38prgsffe8yyef7786ntnqskcz0sqc73" + }, + { + "amount": { + "amount": "97437142", + "denom": "bnb" + }, + "cdp_id": "799", + "depositor": "kava1xq8ffuznqtu733gvazlfpgplkrj9wg3nyl79jr" + }, + { + "amount": { + "amount": "4316246000", + "denom": "bnb" + }, + "cdp_id": "801", + "depositor": "kava1vr30pdhcj4xp3kkft0gnhujrxvgrpgw9jvtdqj" + }, + { + "amount": { + "amount": "15051100578", + "denom": "bnb" + }, + "cdp_id": "804", + "depositor": "kava14s6k9l2hqesptr0erwlpu70t36922wvm5qz8lt" + }, + { + "amount": { + "amount": "226017050", + "denom": "bnb" + }, + "cdp_id": "805", + "depositor": "kava1ddgfxvftrdx372n3y8hqzmgafd4p4km8s9xalq" + }, + { + "amount": { + "amount": "98454000", + "denom": "bnb" + }, + "cdp_id": "806", + "depositor": "kava1zuslhtgj5r8n95k833w5lttnjzuxcpjy7ql3c5" + }, + { + "amount": { + "amount": "499998000", + "denom": "bnb" + }, + "cdp_id": "812", + "depositor": "kava103ykgmuyj782yznegdeph5yvj89w26aaw0mnt8" + }, + { + "amount": { + "amount": "460691000", + "denom": "bnb" + }, + "cdp_id": "813", + "depositor": "kava1vgxww69ecwvwl36d4k8a6errsfrm408t4gpzft" + }, + { + "amount": { + "amount": "259700000", + "denom": "bnb" + }, + "cdp_id": "818", + "depositor": "kava1tl2prafjdaxdq7y7rk9820r0xp0merzud4ttkn" + }, + { + "amount": { + "amount": "51499861500", + "denom": "bnb" + }, + "cdp_id": "823", + "depositor": "kava1dwek8s78xay76gcflqd0jyn6fxmqt2yzzgfdh3" + }, + { + "amount": { + "amount": "26718603459", + "denom": "bnb" + }, + "cdp_id": "827", + "depositor": "kava1au8ulcadj99qjr8vanzzyh5msgq3577xsxacsj" + }, + { + "amount": { + "amount": "125000000", + "denom": "bnb" + }, + "cdp_id": "829", + "depositor": "kava18fz46zf48x74yhsrrqd6upvkw67yja2jts9q8j" + }, + { + "amount": { + "amount": "658020000", + "denom": "bnb" + }, + "cdp_id": "831", + "depositor": "kava1jv2j4spatvrx65w7u75jxlp4p7duu7989nq22u" + }, + { + "amount": { + "amount": "25860718548", + "denom": "bnb" + }, + "cdp_id": "834", + "depositor": "kava10cgh5yf932zs5yaxhdf0rzzy2392f4uf5fs0a7" + }, + { + "amount": { + "amount": "1199999000", + "denom": "bnb" + }, + "cdp_id": "835", + "depositor": "kava163r2fakg3xdvjy3vrq3a84f6fxxduetrj93lrk" + }, + { + "amount": { + "amount": "237746000", + "denom": "bnb" + }, + "cdp_id": "837", + "depositor": "kava1a5s9spedfgcskr8cvf45w00m4exw066tjjg6sx" + }, + { + "amount": { + "amount": "204080858", + "denom": "bnb" + }, + "cdp_id": "838", + "depositor": "kava1yxhjnc3u2avecdqwj63n4xeymg958ausnjf8w7" + }, + { + "amount": { + "amount": "900000000", + "denom": "bnb" + }, + "cdp_id": "839", + "depositor": "kava1ygratzmlvzz3nrzu4anfeq4yaturdv5eq7hfa2" + }, + { + "amount": { + "amount": "917984131", + "denom": "bnb" + }, + "cdp_id": "842", + "depositor": "kava1984kwcqxsr0gee5e7egtmlfah6lxt03xwz363f" + }, + { + "amount": { + "amount": "4613807813", + "denom": "bnb" + }, + "cdp_id": "845", + "depositor": "kava13gjy32eew2x2snde9g7j64zz2vwmttupm6vs5t" + }, + { + "amount": { + "amount": "983761500", + "denom": "bnb" + }, + "cdp_id": "846", + "depositor": "kava1ze3euftmkdlt9e2smv0r3v3hn3v5xx7nnycm59" + }, + { + "amount": { + "amount": "220000000", + "denom": "bnb" + }, + "cdp_id": "853", + "depositor": "kava10gytfpmnffydm83at2hff3yuydnnzz2lghvely" + }, + { + "amount": { + "amount": "6216492198", + "denom": "bnb" + }, + "cdp_id": "854", + "depositor": "kava1r8s9re6r6ak23u0ue6nsa7pfrthgfzergxf3gn" + }, + { + "amount": { + "amount": "2479823000", + "denom": "bnb" + }, + "cdp_id": "855", + "depositor": "kava1ltu99e6nyvvuzpcx580uj5r2nee4zfep0d2e9q" + }, + { + "amount": { + "amount": "491861500", + "denom": "bnb" + }, + "cdp_id": "859", + "depositor": "kava19g7zfe7ncrxtmehsth0m6qklas9ywzxdqnenge" + }, + { + "amount": { + "amount": "125816092", + "denom": "bnb" + }, + "cdp_id": "860", + "depositor": "kava1e3c3wg748svce49arajje3quzk80ltqxknhggz" + }, + { + "amount": { + "amount": "170251594", + "denom": "bnb" + }, + "cdp_id": "862", + "depositor": "kava1rvjeepvt9snpa7m7x5kccmy3287vqj5rcmzamz" + }, + { + "amount": { + "amount": "30104997000", + "denom": "bnb" + }, + "cdp_id": "863", + "depositor": "kava1hag49aychydfefvenqe38yedwly95sey0dae4m" + }, + { + "amount": { + "amount": "1499980250", + "denom": "bnb" + }, + "cdp_id": "865", + "depositor": "kava1evgktxw4kwmx2skpqdg8rj0czxu922e4wptvt2" + }, + { + "amount": { + "amount": "296360659", + "denom": "bnb" + }, + "cdp_id": "866", + "depositor": "kava1fu6w9xrfk0a9w3sgraln2mfvk3h6h05tfenr2w" + }, + { + "amount": { + "amount": "142350000", + "denom": "bnb" + }, + "cdp_id": "869", + "depositor": "kava1z3rzlk084qnkrt0k0r73q2l7y88cvz52ywhejn" + }, + { + "amount": { + "amount": "705993610", + "denom": "bnb" + }, + "cdp_id": "870", + "depositor": "kava1flsflys3g7sjs07tfrr0gvl56w6sqepw7zs4sd" + }, + { + "amount": { + "amount": "1999999000", + "denom": "bnb" + }, + "cdp_id": "871", + "depositor": "kava1zpd87f3jjw5hmxc7rm0wd3k85x7e8qcntwn8gl" + }, + { + "amount": { + "amount": "98556000", + "denom": "bnb" + }, + "cdp_id": "878", + "depositor": "kava149fsfmyz5790sv2r6xvf95mtytu9xm0nq6f8uv" + }, + { + "amount": { + "amount": "4958326340", + "denom": "bnb" + }, + "cdp_id": "881", + "depositor": "kava1gz8hhxxl99y8cy0vray6dy8zwgkymyfvj2tgjn" + }, + { + "amount": { + "amount": "91305924", + "denom": "bnb" + }, + "cdp_id": "882", + "depositor": "kava132d7r249567tjtfs4n2le29jeeg40jp9yemtsk" + }, + { + "amount": { + "amount": "84318940", + "denom": "bnb" + }, + "cdp_id": "885", + "depositor": "kava1gy8n6g26eqjf0k8nlxv0t88r34lnp7jgtg9s2p" + }, + { + "amount": { + "amount": "1734167463466", + "denom": "bnb" + }, + "cdp_id": "886", + "depositor": "kava1tstf3u4cw7u4xyu7wxdrnmrpvvmfamq3twcj7f" + }, + { + "amount": { + "amount": "5187777610", + "denom": "bnb" + }, + "cdp_id": "890", + "depositor": "kava1nx4ea0h0dhef880l920nw908dkkqdrwrlcc56y" + }, + { + "amount": { + "amount": "116271716", + "denom": "bnb" + }, + "cdp_id": "891", + "depositor": "kava10xdmc0zj4pg5lqxf885ljezzk6t30du5gqmgvx" + }, + { + "amount": { + "amount": "200168819", + "denom": "bnb" + }, + "cdp_id": "892", + "depositor": "kava1my6zpnmut99u85rj50fvrnyfer6pf5kp8d74j3" + }, + { + "amount": { + "amount": "599999000", + "denom": "bnb" + }, + "cdp_id": "894", + "depositor": "kava1s454se9qfvaajfdh2c7vkt2u9fwvkfkvzy3a4w" + }, + { + "amount": { + "amount": "940385500", + "denom": "bnb" + }, + "cdp_id": "898", + "depositor": "kava1lzjfwjzmlf376fnhj6gpvzy446664tvzn649hw" + }, + { + "amount": { + "amount": "249923000", + "denom": "bnb" + }, + "cdp_id": "899", + "depositor": "kava1hg54sx9l9c6xc4m5sul5j9tgs3srnyxzvj8l4z" + }, + { + "amount": { + "amount": "349723000", + "denom": "bnb" + }, + "cdp_id": "900", + "depositor": "kava1x4phjjj9sg6tqgc660tl59fskk68ywsvm5hjv5" + }, + { + "amount": { + "amount": "1666305551", + "denom": "bnb" + }, + "cdp_id": "901", + "depositor": "kava1v7veexlrmz2n5v4jw3ngdgu83fyazej7hwwjy7" + }, + { + "amount": { + "amount": "898545000", + "denom": "bnb" + }, + "cdp_id": "902", + "depositor": "kava16jrh3q9c0j96q3gettqrg7s2lpgvzr4f5u0gfp" + }, + { + "amount": { + "amount": "199761500", + "denom": "bnb" + }, + "cdp_id": "903", + "depositor": "kava13wtz6ae3j7t6n3fs5uwu5pyjkz93zh7n30nys9" + }, + { + "amount": { + "amount": "62000000", + "denom": "bnb" + }, + "cdp_id": "904", + "depositor": "kava1mrv7gwmwj4s9se2tvae0gv89pelax3tugfl7js" + }, + { + "amount": { + "amount": "19949995500", + "denom": "bnb" + }, + "cdp_id": "905", + "depositor": "kava16mue32jztkv7rzp50k6r23wx6nlnyyh0xr0u7t" + }, + { + "amount": { + "amount": "99442669", + "denom": "bnb" + }, + "cdp_id": "906", + "depositor": "kava1cltnlz37arf9ywkkx6kj6u4qmjtm55h5yey0xr" + }, + { + "amount": { + "amount": "1030630957", + "denom": "bnb" + }, + "cdp_id": "909", + "depositor": "kava1shqxy33cvadpzsm7lcyruwyjufcd6zqemjhtff" + }, + { + "amount": { + "amount": "710761500", + "denom": "bnb" + }, + "cdp_id": "911", + "depositor": "kava1pt43yyefq2xu7zpuczqmt595wfmeh2ha2qu4r2" + }, + { + "amount": { + "amount": "683167180", + "denom": "bnb" + }, + "cdp_id": "914", + "depositor": "kava1e3fvhwlltc22g90vpcxjqghd7vf8u5wllsvf8h" + }, + { + "amount": { + "amount": "104360500", + "denom": "bnb" + }, + "cdp_id": "915", + "depositor": "kava163hks4cek5jg6p2ywk3f06vy6gh7pkltlmcjsl" + }, + { + "amount": { + "amount": "86144912", + "denom": "bnb" + }, + "cdp_id": "922", + "depositor": "kava1gsmesaau9nwaz0tpaal758e9uvadlxwh4d4jyz" + }, + { + "amount": { + "amount": "210845917", + "denom": "bnb" + }, + "cdp_id": "924", + "depositor": "kava1l94lp2rg58cxkp8yz0yczezd5v5aem7v33dg95" + }, + { + "amount": { + "amount": "91910854", + "denom": "bnb" + }, + "cdp_id": "925", + "depositor": "kava1jpcz2nje3ahnkejxyrhvzdnyftm5sfcg6mzt3f" + }, + { + "amount": { + "amount": "3422784750", + "denom": "bnb" + }, + "cdp_id": "927", + "depositor": "kava1w22appkhcuy3ll4mpz67d35fl9wcv7ydf2k9zu" + }, + { + "amount": { + "amount": "100000000", + "denom": "bnb" + }, + "cdp_id": "937", + "depositor": "kava18fvar39w22u2juwwmd8ve93707gpx98qq99p9q" + }, + { + "amount": { + "amount": "5000373638", + "denom": "bnb" + }, + "cdp_id": "940", + "depositor": "kava1l5xk08pn8cwwsd8gzgvgh5ef9n7e57fgm058rp" + }, + { + "amount": { + "amount": "497603973", + "denom": "bnb" + }, + "cdp_id": "943", + "depositor": "kava17rw3tlpwj4sr8xvhfpz5vv7a33zc7gzpnr57la" + }, + { + "amount": { + "amount": "1049999000", + "denom": "bnb" + }, + "cdp_id": "954", + "depositor": "kava1z4flv307tmd77y7u66d5w27s90vcffjfzq9ee2" + }, + { + "amount": { + "amount": "499861500", + "denom": "bnb" + }, + "cdp_id": "959", + "depositor": "kava1tlgk8pxwcvkdxkgcc9fqfyu4qxg7thyzn0rhdr" + }, + { + "amount": { + "amount": "2549999000", + "denom": "bnb" + }, + "cdp_id": "960", + "depositor": "kava1dqswms7d6javy8pv73r9v2sxgplurkkmfq5wpn" + }, + { + "amount": { + "amount": "100000000", + "denom": "bnb" + }, + "cdp_id": "961", + "depositor": "kava1suqkqpuxl5a9acajzfyr625jysevg8j67hwv2t" + }, + { + "amount": { + "amount": "100396886", + "denom": "bnb" + }, + "cdp_id": "962", + "depositor": "kava1dlyzmepcm60cj36jt2zet2jellkdm5uzjgj46r" + }, + { + "amount": { + "amount": "100000000", + "denom": "bnb" + }, + "cdp_id": "963", + "depositor": "kava130rux6nveq6f7w7y34h736akupz0y73v3c6xv0" + }, + { + "amount": { + "amount": "99507500", + "denom": "bnb" + }, + "cdp_id": "966", + "depositor": "kava1ds3nf2q3ar8qprt0a0q2gw7ze7xy2hvqn8nyst" + }, + { + "amount": { + "amount": "1823584500", + "denom": "bnb" + }, + "cdp_id": "968", + "depositor": "kava1966kjxa5n9vg3te7khrx3zwg02pleemd04mffx" + }, + { + "amount": { + "amount": "99861500", + "denom": "bnb" + }, + "cdp_id": "970", + "depositor": "kava1vjsnhq5h0jx6lnts3lf5rvc7nkenzngxjx4stl" + }, + { + "amount": { + "amount": "1799861500", + "denom": "bnb" + }, + "cdp_id": "971", + "depositor": "kava1vd4sh2z04wk8r3uq35defp8ermgwrqnvlw89s8" + }, + { + "amount": { + "amount": "1028897371", + "denom": "bnb" + }, + "cdp_id": "973", + "depositor": "kava1pccn7ea8lvs5uqy7uv4d5s0n2l5chvfqhfqu45" + }, + { + "amount": { + "amount": "6444459575", + "denom": "bnb" + }, + "cdp_id": "974", + "depositor": "kava13w0kf4f77cmjtgm5yvjqmqnjtyd92ukazdk0re" + }, + { + "amount": { + "amount": "100000000", + "denom": "bnb" + }, + "cdp_id": "976", + "depositor": "kava16jpf48k46ta6j3efptnf7vup7kp7qq3jkmhu36" + }, + { + "amount": { + "amount": "600000000", + "denom": "bnb" + }, + "cdp_id": "977", + "depositor": "kava1ucce4lcy7mhnwqrkpys90ukc0nrt0700jg0t2u" + }, + { + "amount": { + "amount": "16009958500", + "denom": "bnb" + }, + "cdp_id": "979", + "depositor": "kava1wcanu7p4anpynf96vy6r5vcphcfdcah5zafrdj" + }, + { + "amount": { + "amount": "66858594", + "denom": "bnb" + }, + "cdp_id": "982", + "depositor": "kava1yc5qftkw3rxcmucy027zx7rfyrsqhms32qfwej" + }, + { + "amount": { + "amount": "77231297342", + "denom": "bnb" + }, + "cdp_id": "984", + "depositor": "kava1un2a96zhymexgdx9ujeldm2a6te9ar66n2en78" + }, + { + "amount": { + "amount": "99823000", + "denom": "bnb" + }, + "cdp_id": "985", + "depositor": "kava1c83e3fqpe2jjgcky22xjawery6spwq7365x430" + }, + { + "amount": { + "amount": "1431906978", + "denom": "bnb" + }, + "cdp_id": "988", + "depositor": "kava1syee72y2ejrqvggynq0lhktkac88gzqffmz04c" + }, + { + "amount": { + "amount": "97364484", + "denom": "bnb" + }, + "cdp_id": "990", + "depositor": "kava19j9hz6gr4tslnjr9ckqjxmd9rreag3kjmrz7nz" + }, + { + "amount": { + "amount": "60227274", + "denom": "bnb" + }, + "cdp_id": "991", + "depositor": "kava1zcmdwg43j0s6ukv23yur5f2qjkatmmapcwsfsq" + }, + { + "amount": { + "amount": "569656569", + "denom": "bnb" + }, + "cdp_id": "992", + "depositor": "kava1q40vl0wqju4upe7gafrzpuvcdev6gez5m747p6" + }, + { + "amount": { + "amount": "61538810", + "denom": "bnb" + }, + "cdp_id": "997", + "depositor": "kava18xvs8ergahd0s3fa40w7ce49mkytg4khtd58nw" + }, + { + "amount": { + "amount": "69861500", + "denom": "bnb" + }, + "cdp_id": "999", + "depositor": "kava10y72033n45jpu8nh26pws764ca62cspql6muln" + }, + { + "amount": { + "amount": "99685103", + "denom": "bnb" + }, + "cdp_id": "1001", + "depositor": "kava1vlzmqht6g3ph0df03zf44r6h0rje5xkfsetlhr" + }, + { + "amount": { + "amount": "199999000", + "denom": "bnb" + }, + "cdp_id": "1012", + "depositor": "kava1lv0x52v8pxletxx75tfw3gjfq0yuhm6jwnefmt" + }, + { + "amount": { + "amount": "500000000", + "denom": "bnb" + }, + "cdp_id": "1013", + "depositor": "kava1q0eza4n6aa2k76zpjfjydeauvk0lgumxxy3f0v" + }, + { + "amount": { + "amount": "292910915", + "denom": "bnb" + }, + "cdp_id": "1025", + "depositor": "kava1t7uk5ds4ru2q56xnty6ryzxkkmaj8qju5r82zh" + }, + { + "amount": { + "amount": "111865103", + "denom": "bnb" + }, + "cdp_id": "1026", + "depositor": "kava1fgmpmaxpqmjjec3tjfjxjmxm9w89vnl5c9cwme" + }, + { + "amount": { + "amount": "89350000", + "denom": "bnb" + }, + "cdp_id": "1028", + "depositor": "kava1xfchqd6ymhw8lp6shzupkz66kj5smyu7lqjqqw" + }, + { + "amount": { + "amount": "152998000", + "denom": "bnb" + }, + "cdp_id": "1029", + "depositor": "kava1y8xxdekejgews0rmtcm3c6qcwvhqcr48le90ju" + }, + { + "amount": { + "amount": "38900000000", + "denom": "bnb" + }, + "cdp_id": "1030", + "depositor": "kava1kthd66zuvu03yk9ase9ju867pl9h493jfrua93" + }, + { + "amount": { + "amount": "298942469", + "denom": "bnb" + }, + "cdp_id": "1034", + "depositor": "kava1m974xquf5w7j043uspalpulxkm0nf48st65mys" + }, + { + "amount": { + "amount": "98152192", + "denom": "bnb" + }, + "cdp_id": "1035", + "depositor": "kava1gmdmcrppy9pv8fyu5apa6majvf3p89nhsczhgz" + }, + { + "amount": { + "amount": "181351271", + "denom": "bnb" + }, + "cdp_id": "1038", + "depositor": "kava18hv6fqwe83jrg7vmark9mspewv6p6u3k5nqskn" + }, + { + "amount": { + "amount": "98572000", + "denom": "bnb" + }, + "cdp_id": "1040", + "depositor": "kava15xc7hkst2huv0sgr4eqw6dr50emwsw894xgwqf" + }, + { + "amount": { + "amount": "2499861500", + "denom": "bnb" + }, + "cdp_id": "1045", + "depositor": "kava125y60srn5rp8ay4j2url380jyvrnjvy6qse609" + }, + { + "amount": { + "amount": "510961500", + "denom": "bnb" + }, + "cdp_id": "1051", + "depositor": "kava1a4ssa9ntvjrva0xvndvapza5saw6d8t66gnzph" + }, + { + "amount": { + "amount": "99861500", + "denom": "bnb" + }, + "cdp_id": "1054", + "depositor": "kava15yns68g0sc5en5h3qdpfs7ydd93n94r0gyuh8d" + }, + { + "amount": { + "amount": "115313787", + "denom": "bnb" + }, + "cdp_id": "1055", + "depositor": "kava13833lua3wuczhdrg2m6antnryyfqzxnjxhxpej" + }, + { + "amount": { + "amount": "96328000", + "denom": "bnb" + }, + "cdp_id": "1056", + "depositor": "kava15ex4ng3943n0eclcjc5zz22rmqy04mgp4wqx6r" + }, + { + "amount": { + "amount": "100000000", + "denom": "bnb" + }, + "cdp_id": "1057", + "depositor": "kava1ztgycvjv9vqjtvn9qp54l7mcczmvr22y4zvspe" + }, + { + "amount": { + "amount": "1009998000", + "denom": "bnb" + }, + "cdp_id": "1058", + "depositor": "kava1wdyd2lpllxk2t9mg3qe5gqlgzvvf08ns380u3g" + }, + { + "amount": { + "amount": "500582500", + "denom": "bnb" + }, + "cdp_id": "1060", + "depositor": "kava1gp7k90kaatayu9cgnzmp02a0dmgfyye67zyup8" + }, + { + "amount": { + "amount": "4773509000", + "denom": "bnb" + }, + "cdp_id": "1062", + "depositor": "kava14pq4u6w5p5qawu8mxhsvahrlfzxq3g544agczl" + }, + { + "amount": { + "amount": "6134992000", + "denom": "bnb" + }, + "cdp_id": "1063", + "depositor": "kava1tzzdns8zkl0qptywnpr27eh0evj9zu45pc8f0g" + }, + { + "amount": { + "amount": "856218750", + "denom": "bnb" + }, + "cdp_id": "1064", + "depositor": "kava1lvwpkfterjc48mmuja4gps0u4k8mwmx5hpyzgm" + }, + { + "amount": { + "amount": "1009684500", + "denom": "bnb" + }, + "cdp_id": "1066", + "depositor": "kava10x9egqv6wyd9mjvtmd4h97hpa7ha259a2t0zux" + }, + { + "amount": { + "amount": "90930528", + "denom": "bnb" + }, + "cdp_id": "1067", + "depositor": "kava1d0qym0r8harr3jhphzeasst8jchhfcx58egdqw" + }, + { + "amount": { + "amount": "102733805", + "denom": "bnb" + }, + "cdp_id": "1068", + "depositor": "kava14dnwu4xmzur37zatgfd3mg8cjphs0k2lkyxyyy" + }, + { + "amount": { + "amount": "1374108876", + "denom": "bnb" + }, + "cdp_id": "1069", + "depositor": "kava10zj8d0kwdfz5v7yhdpkxpwcmgr44yhg6da58dm" + }, + { + "amount": { + "amount": "2799861500", + "denom": "bnb" + }, + "cdp_id": "1071", + "depositor": "kava1nh9l69guvs8apf74mqgp7yyfgddd3pnx9tfdpw" + }, + { + "amount": { + "amount": "175081938", + "denom": "bnb" + }, + "cdp_id": "1072", + "depositor": "kava1f9gr72w4f5x8e6n4naaqh9ep64qsut87227yy3" + }, + { + "amount": { + "amount": "354856061", + "denom": "bnb" + }, + "cdp_id": "1073", + "depositor": "kava1e9zw63uwaz3jhejq2f2pv9dkg3y2vafq4v2d60" + }, + { + "amount": { + "amount": "4656753500", + "denom": "bnb" + }, + "cdp_id": "1075", + "depositor": "kava1a6gehaye2j5gnv0v2670n8mg40sc5z44nxj8lh" + }, + { + "amount": { + "amount": "99281838", + "denom": "bnb" + }, + "cdp_id": "1077", + "depositor": "kava17uvhem6mefz6qqacu6w455d6af48qtqg4zcrrg" + }, + { + "amount": { + "amount": "199722000", + "denom": "bnb" + }, + "cdp_id": "1078", + "depositor": "kava1dlhhf0jewx7m0j5nsm8gkke32ytggxk0dx436z" + }, + { + "amount": { + "amount": "881354038", + "denom": "bnb" + }, + "cdp_id": "1079", + "depositor": "kava17lc8kscue95emdyaswhhh8narnxct7klrgp544" + }, + { + "amount": { + "amount": "500000000", + "denom": "bnb" + }, + "cdp_id": "1080", + "depositor": "kava17h0a2xr7c6e0e2eyp2jhpg6udkgrg6vrdf85wr" + }, + { + "amount": { + "amount": "25479494037", + "denom": "bnb" + }, + "cdp_id": "1081", + "depositor": "kava1kyq6kgxvsfd4w4km43hcqv6jejnmu78q8cj0l7" + }, + { + "amount": { + "amount": "20599723000", + "denom": "bnb" + }, + "cdp_id": "1082", + "depositor": "kava1frqzm6zcjnn8fwq46tfchn64vyvp4lma7440sw" + }, + { + "amount": { + "amount": "117363612", + "denom": "bnb" + }, + "cdp_id": "1084", + "depositor": "kava1madvye95n3pps3g42s2g33e8nz6yg0m4eqad23" + }, + { + "amount": { + "amount": "98306194", + "denom": "bnb" + }, + "cdp_id": "1086", + "depositor": "kava18v3u8ehl46kkujm6mzp2faqwdhk6dc3j48jzv5" + }, + { + "amount": { + "amount": "105146500", + "denom": "bnb" + }, + "cdp_id": "1087", + "depositor": "kava1tgs73yuhrg32cnlc09r7r7v9r5l96j2tegmxmj" + }, + { + "amount": { + "amount": "80000000", + "denom": "bnb" + }, + "cdp_id": "1089", + "depositor": "kava1h8kqkqlgcnl09djvxfz7j68ct8q79x5vf4zdjt" + }, + { + "amount": { + "amount": "410000000", + "denom": "bnb" + }, + "cdp_id": "1092", + "depositor": "kava1xevtu9l5n5ztx65xnlyp6wwkl28curelc8wpkx" + }, + { + "amount": { + "amount": "59805500", + "denom": "bnb" + }, + "cdp_id": "1095", + "depositor": "kava1a0kkecrgvuvume6el50u7pvxnqn8xrpkn9j64z" + }, + { + "amount": { + "amount": "8399999000", + "denom": "bnb" + }, + "cdp_id": "1097", + "depositor": "kava1gf2a33yz07peuk0xzhg7w0nrhs03858ewnck5k" + }, + { + "amount": { + "amount": "541492075", + "denom": "bnb" + }, + "cdp_id": "1100", + "depositor": "kava13cc9ysrtqw4uzalgfyzt2ezlj4sdu8tfdrw57v" + }, + { + "amount": { + "amount": "999999000", + "denom": "bnb" + }, + "cdp_id": "1101", + "depositor": "kava1ju72ykesecrggfk35uawdtgjxdxqcpjla5n6c0" + }, + { + "amount": { + "amount": "1634909684", + "denom": "bnb" + }, + "cdp_id": "1103", + "depositor": "kava1lgfa45c9ukzxmtfhdmx0k4dnt4whph28csdds3" + }, + { + "amount": { + "amount": "183861500", + "denom": "bnb" + }, + "cdp_id": "1107", + "depositor": "kava1su2zgzekk4xqn53z68jqnz4w6djl2vf76qh2de" + }, + { + "amount": { + "amount": "2399995000", + "denom": "bnb" + }, + "cdp_id": "1108", + "depositor": "kava1vkhtmn2awzg2wsu9uujw455kcce2msxc078325" + }, + { + "amount": { + "amount": "667867478", + "denom": "bnb" + }, + "cdp_id": "1109", + "depositor": "kava14y0c4e883xwr3mp0wexvnp6knsd4me62ampna8" + }, + { + "amount": { + "amount": "1199999000", + "denom": "bnb" + }, + "cdp_id": "1110", + "depositor": "kava16fkalpvmzvs2jnr2nemwnna53d60pf4mrjvtfd" + }, + { + "amount": { + "amount": "346257612", + "denom": "bnb" + }, + "cdp_id": "1111", + "depositor": "kava1fzptzt0cr88ne6ly4kts0pwnm7c4kxkuu5zxas" + }, + { + "amount": { + "amount": "196861500", + "denom": "bnb" + }, + "cdp_id": "1112", + "depositor": "kava1lz0dv3tanz398yt4tfgnddah0desphmekk67cg" + }, + { + "amount": { + "amount": "314898833", + "denom": "bnb" + }, + "cdp_id": "1114", + "depositor": "kava1p8azx3q0r3r7j9u8rrlcjmgadsuz0vnvufweg3" + }, + { + "amount": { + "amount": "1589661500", + "denom": "bnb" + }, + "cdp_id": "1115", + "depositor": "kava1dmfc20gm0f4lnu0fuuq7c24tyjrdurfkfp49dm" + }, + { + "amount": { + "amount": "93525560", + "denom": "bnb" + }, + "cdp_id": "1116", + "depositor": "kava1w0grk3qszlmcas2dwqvq5ayehgpwqfrhj3gxsn" + }, + { + "amount": { + "amount": "1069338027", + "denom": "bnb" + }, + "cdp_id": "1120", + "depositor": "kava1n8y0wh5aau0ke9q9jp9zapjnxxd87mwdvhr0p5" + }, + { + "amount": { + "amount": "96046900", + "denom": "bnb" + }, + "cdp_id": "1121", + "depositor": "kava1skjcua56k0cmvndwscadl7u46v52veyyynglra" + }, + { + "amount": { + "amount": "799584500", + "denom": "bnb" + }, + "cdp_id": "1122", + "depositor": "kava16h66fzp2p63ayhvuacss6r4tvhsjs0qf6u472h" + }, + { + "amount": { + "amount": "94213574", + "denom": "bnb" + }, + "cdp_id": "1123", + "depositor": "kava1s3pem3p4vtgszlas2qv9hkxa43xms9fhdk23x3" + }, + { + "amount": { + "amount": "410161543", + "denom": "bnb" + }, + "cdp_id": "1124", + "depositor": "kava1ugg73fn4x5urnxyzzxc60qksnpjwjdnhh03sjp" + }, + { + "amount": { + "amount": "4999961500", + "denom": "bnb" + }, + "cdp_id": "1125", + "depositor": "kava1mkh4v9zpxc3g0zkjf8c2vt2pue2xce2yxkr8s0" + }, + { + "amount": { + "amount": "1060204111", + "denom": "bnb" + }, + "cdp_id": "1127", + "depositor": "kava1zend29hj3dh3e6ksvp05dls700jehajw2qgp2z" + }, + { + "amount": { + "amount": "847923000", + "denom": "bnb" + }, + "cdp_id": "1128", + "depositor": "kava1krfy0mvum7gve4k3zwakny4ywyw9444v2clryc" + }, + { + "amount": { + "amount": "99999000", + "denom": "bnb" + }, + "cdp_id": "1129", + "depositor": "kava1tkk7z4w7kc8c3uf85ypjq2ch5x2h7ardrwykrv" + }, + { + "amount": { + "amount": "79191665", + "denom": "bnb" + }, + "cdp_id": "1130", + "depositor": "kava1rau6y74vp3exf0we0skz8h2ps3srtvymz0c2m0" + }, + { + "amount": { + "amount": "647420107", + "denom": "bnb" + }, + "cdp_id": "1131", + "depositor": "kava19e7mx9ajlmztzaysx0xp65y3xwud7juamajmwx" + }, + { + "amount": { + "amount": "2749724000", + "denom": "bnb" + }, + "cdp_id": "1132", + "depositor": "kava1qql0h04u6n244uu4gzpl8fegpzfk30t8qfmeyd" + }, + { + "amount": { + "amount": "2079961500", + "denom": "bnb" + }, + "cdp_id": "1133", + "depositor": "kava1m32nfspk6l4ywdrv2mxwyz75s2tujcrct2sxys" + }, + { + "amount": { + "amount": "84103000", + "denom": "bnb" + }, + "cdp_id": "1136", + "depositor": "kava14ewkuy3szkkdhdsgy4k87xcg67tvujnsm7arr9" + }, + { + "amount": { + "amount": "99961500", + "denom": "bnb" + }, + "cdp_id": "1137", + "depositor": "kava1d7h24gvk2hzq5ysycz7ras8ylzmraym4xar204" + }, + { + "amount": { + "amount": "149999000", + "denom": "bnb" + }, + "cdp_id": "1138", + "depositor": "kava1a4th2q9fvv6q5ssfrx8flly09dcn9g3s4lqy4h" + }, + { + "amount": { + "amount": "121770000", + "denom": "bnb" + }, + "cdp_id": "1139", + "depositor": "kava15u9yth0fyg8e9cde7smsxdezj2w07afnc2ygwk" + }, + { + "amount": { + "amount": "220793241", + "denom": "bnb" + }, + "cdp_id": "1140", + "depositor": "kava1sf9fkql92spg0nqyjqlyrvv9ty2e7dqt6a374m" + }, + { + "amount": { + "amount": "99310452", + "denom": "bnb" + }, + "cdp_id": "1142", + "depositor": "kava1688jl7fanlpnrc22wen368g8879662eu0yfk7j" + }, + { + "amount": { + "amount": "1244050055", + "denom": "bnb" + }, + "cdp_id": "1144", + "depositor": "kava12qq5jfczwdtz3682nretdw29fwceeeug3cv767" + }, + { + "amount": { + "amount": "199999000", + "denom": "bnb" + }, + "cdp_id": "1145", + "depositor": "kava1jr58355f3waf98sujfshuzf2qk7s63tqh90fy5" + }, + { + "amount": { + "amount": "864235131", + "denom": "bnb" + }, + "cdp_id": "1146", + "depositor": "kava187vqgkz0p4279ckuf4lnuk3zrxz3w92r3jzflh" + }, + { + "amount": { + "amount": "609861500", + "denom": "bnb" + }, + "cdp_id": "1149", + "depositor": "kava1qjsh569wv0frufrzescdu38rxmdvxfwsqee253" + }, + { + "amount": { + "amount": "3201052123", + "denom": "bnb" + }, + "cdp_id": "1150", + "depositor": "kava19w04elv89rwygj4t6qf4cwq5fpdgcfn03k740f" + }, + { + "amount": { + "amount": "349571500", + "denom": "bnb" + }, + "cdp_id": "1151", + "depositor": "kava13ahfrdmr383r5skkxqecn3zjk93kjdjtvat22a" + }, + { + "amount": { + "amount": "401204683", + "denom": "bnb" + }, + "cdp_id": "1154", + "depositor": "kava1nxg24gzzh9k8pl06frvp7989g3kk4ualgqkylx" + }, + { + "amount": { + "amount": "2197108459", + "denom": "bnb" + }, + "cdp_id": "1155", + "depositor": "kava16l9y9utg6j8u0vk3mcrdu7xampr4z24xuxr58g" + }, + { + "amount": { + "amount": "499999000", + "denom": "bnb" + }, + "cdp_id": "1156", + "depositor": "kava1ce4c7qc9zyfp45emhvjjy8470xwastdca2qxjg" + }, + { + "amount": { + "amount": "4899999000", + "denom": "bnb" + }, + "cdp_id": "1157", + "depositor": "kava1qyuxcegvmxphwsm34gf0l3l9ldxn0zfmj9pazu" + }, + { + "amount": { + "amount": "699998000", + "denom": "bnb" + }, + "cdp_id": "1160", + "depositor": "kava1yrzmk4y24da8kn9c84w7pxkpjfntmszmh5rr9l" + }, + { + "amount": { + "amount": "37200000000", + "denom": "bnb" + }, + "cdp_id": "1163", + "depositor": "kava1xzqca09l2nkrjqtrqwqe4l3fj5hzc685c6dl2h" + }, + { + "amount": { + "amount": "181723000", + "denom": "bnb" + }, + "cdp_id": "1164", + "depositor": "kava145cfm44fzv87gg3yudqkqj8ejmff5252agwpsu" + }, + { + "amount": { + "amount": "267399000", + "denom": "bnb" + }, + "cdp_id": "1165", + "depositor": "kava1k738mvz97wp93h97jj5f7jvxurkypay3tr0xmc" + }, + { + "amount": { + "amount": "199961500", + "denom": "bnb" + }, + "cdp_id": "1168", + "depositor": "kava1z6j0d4352ljna6rjgcr8d5cl4mt3tsng0z9dux" + }, + { + "amount": { + "amount": "6400814130", + "denom": "bnb" + }, + "cdp_id": "1169", + "depositor": "kava10zl70qnnf0wgxx6eu9mn6k0tmrn0yqevsxv806" + }, + { + "amount": { + "amount": "15299723000", + "denom": "bnb" + }, + "cdp_id": "1170", + "depositor": "kava1q74kea59tmpelupa7mkq6cj697l07cjmnf4l5j" + }, + { + "amount": { + "amount": "129884500", + "denom": "bnb" + }, + "cdp_id": "1172", + "depositor": "kava1hmgz6wjr6gwehda53zy7r74tteyx7pvqtw9d59" + }, + { + "amount": { + "amount": "187224202", + "denom": "bnb" + }, + "cdp_id": "1173", + "depositor": "kava1vrdmnppmyfas5vuqj8wdm847gatvf9ehg4k5ej" + }, + { + "amount": { + "amount": "604137456", + "denom": "bnb" + }, + "cdp_id": "1174", + "depositor": "kava1zfsfrdyhyuyw462r3e358aj43r2nsp9vexp2vc" + }, + { + "amount": { + "amount": "101521504", + "denom": "bnb" + }, + "cdp_id": "1176", + "depositor": "kava12l48p8ldfkgxwpdyhqavy2psfzapc8jx5g649k" + }, + { + "amount": { + "amount": "99167445", + "denom": "bnb" + }, + "cdp_id": "1177", + "depositor": "kava1w0z0u03vcl3pt9yfxls2anfxr7s23d70dhkgvz" + }, + { + "amount": { + "amount": "441821492", + "denom": "bnb" + }, + "cdp_id": "1178", + "depositor": "kava1288mlnjrrp0zckg36f08v47a2qfq6v3tlmppnz" + }, + { + "amount": { + "amount": "141671045", + "denom": "bnb" + }, + "cdp_id": "1180", + "depositor": "kava1tu2zvgn3q6ukz9kc0j65z2dgzd25re3gwnjp2n" + }, + { + "amount": { + "amount": "419417553", + "denom": "bnb" + }, + "cdp_id": "1181", + "depositor": "kava13yml6zhu6xspua5kn8rrwxwr8mpqwcn8u7znsl" + }, + { + "amount": { + "amount": "75109023", + "denom": "bnb" + }, + "cdp_id": "1182", + "depositor": "kava1ncaqhfhug3lxkj99vv0wqjkm29388vtdy0h3e4" + }, + { + "amount": { + "amount": "6038886034", + "denom": "bnb" + }, + "cdp_id": "1183", + "depositor": "kava18jmkxet5tr0eyrklk2zctcjegu6zdkudmgkqpn" + }, + { + "amount": { + "amount": "27094688909", + "denom": "bnb" + }, + "cdp_id": "1184", + "depositor": "kava1f9qfd6vxluuv7tj0wdnwgv5paskq208jhzan0s" + }, + { + "amount": { + "amount": "146953276", + "denom": "bnb" + }, + "cdp_id": "1186", + "depositor": "kava1yc7aedn8a3k99yvknp877gg5spwtgverz9wcww" + }, + { + "amount": { + "amount": "135648304", + "denom": "bnb" + }, + "cdp_id": "1187", + "depositor": "kava1ljcfr9vcl7pe8k0vcrsf5tad80mmac2twq6t2e" + }, + { + "amount": { + "amount": "105300039", + "denom": "bnb" + }, + "cdp_id": "1188", + "depositor": "kava1yu5d5wugkr3ed2rmxkyd3kq36jx7hdg8phmfz3" + }, + { + "amount": { + "amount": "62196553", + "denom": "bnb" + }, + "cdp_id": "1190", + "depositor": "kava1d9kgaeuj2k66585pc5rnc0fmyk4hd462v8hera" + }, + { + "amount": { + "amount": "194292500", + "denom": "bnb" + }, + "cdp_id": "1191", + "depositor": "kava14pafwfsn42jtlk6syjfvuzde5klr9q8srf2uxl" + }, + { + "amount": { + "amount": "1153083837", + "denom": "bnb" + }, + "cdp_id": "1192", + "depositor": "kava1gk4qrjfylpvkrl8phpnxkdrm0yf5w3l4hw9uzh" + }, + { + "amount": { + "amount": "429020826", + "denom": "bnb" + }, + "cdp_id": "1195", + "depositor": "kava10lffqz334n4feznc9ys9z0tpcu57qlw2n78afr" + }, + { + "amount": { + "amount": "3999961500", + "denom": "bnb" + }, + "cdp_id": "1196", + "depositor": "kava1gdgx34jhu0hjvaq5wuzwaapa8cg8mc2jmc4v4w" + }, + { + "amount": { + "amount": "400000000", + "denom": "bnb" + }, + "cdp_id": "1198", + "depositor": "kava1cqwh57xurahm5dyq4ye2f7aelcsqh7m6kqp08x" + }, + { + "amount": { + "amount": "500761500", + "denom": "bnb" + }, + "cdp_id": "1199", + "depositor": "kava1f267je8z7j8hhx8zhe457ucrgzc98sjrh2jjpx" + }, + { + "amount": { + "amount": "156162066", + "denom": "bnb" + }, + "cdp_id": "1200", + "depositor": "kava1rdy5aphvh5pw2tuv0u3l5mfqx5zwutatcyjf48" + }, + { + "amount": { + "amount": "4306960500", + "denom": "bnb" + }, + "cdp_id": "1201", + "depositor": "kava1r7uckqzflqdqcwllh3ty36qvzl0z7utv5ujh3l" + }, + { + "amount": { + "amount": "1189610500", + "denom": "bnb" + }, + "cdp_id": "1202", + "depositor": "kava1c5lzj543l3xlz8s4s03phkkm4p0g6qg570vjys" + }, + { + "amount": { + "amount": "1570133310", + "denom": "bnb" + }, + "cdp_id": "1203", + "depositor": "kava10p3y2uvu36ywvtaf98m07c8wgm0ud4cre8z4ty" + }, + { + "amount": { + "amount": "599861500", + "denom": "bnb" + }, + "cdp_id": "1206", + "depositor": "kava1gvnvk9v46eaecfnq46x9e4wtq9snku77ne7c0f" + }, + { + "amount": { + "amount": "499961500", + "denom": "bnb" + }, + "cdp_id": "1208", + "depositor": "kava18ptdegs5fezrq8eyqemwyhfhpjwwsch66ve9yd" + }, + { + "amount": { + "amount": "100301500", + "denom": "bnb" + }, + "cdp_id": "1210", + "depositor": "kava1my9zsmtzxceytqfhtun6mahtpx4yr5cq4s5uqr" + }, + { + "amount": { + "amount": "95817622", + "denom": "bnb" + }, + "cdp_id": "1211", + "depositor": "kava19javdflgtlzpshn2r5xqlzwfy3h3dada7344xh" + }, + { + "amount": { + "amount": "116463505", + "denom": "bnb" + }, + "cdp_id": "1212", + "depositor": "kava1qct3ma2vxr22hmnm50p538540ngf65jnmffvgy" + }, + { + "amount": { + "amount": "255486630", + "denom": "bnb" + }, + "cdp_id": "1213", + "depositor": "kava160e4kdajay7784je5gvfeey8ufpglmr6gy0564" + }, + { + "amount": { + "amount": "1000026811", + "denom": "bnb" + }, + "cdp_id": "1215", + "depositor": "kava140xym4ugfwtqy6kdrrhvptrm0teah9t6vt5kup" + }, + { + "amount": { + "amount": "1399961500", + "denom": "bnb" + }, + "cdp_id": "1216", + "depositor": "kava14yh6p6n0kl5v6qr6z448sqzmn9lplkwqn0c8jz" + }, + { + "amount": { + "amount": "258921500", + "denom": "bnb" + }, + "cdp_id": "1219", + "depositor": "kava166fuedyd35g57vuuvwyr9pfdl47xqn7ag0unga" + }, + { + "amount": { + "amount": "99961500", + "denom": "bnb" + }, + "cdp_id": "1221", + "depositor": "kava1gfca993p3ety784mhed7cqfgjln9n622u4p49x" + }, + { + "amount": { + "amount": "1251061946", + "denom": "bnb" + }, + "cdp_id": "1222", + "depositor": "kava1er6s83mm2madft79f37ewe2ljlya30awgcrp9d" + }, + { + "amount": { + "amount": "599923000", + "denom": "bnb" + }, + "cdp_id": "1225", + "depositor": "kava12z9k00k7dje9vnpfkkqsr0e7fy795dqjjugqn8" + }, + { + "amount": { + "amount": "699923000", + "denom": "bnb" + }, + "cdp_id": "1227", + "depositor": "kava1qutky6rkm8002vsd5mf39wfujr9lpgehevf3ny" + }, + { + "amount": { + "amount": "1842478500", + "denom": "bnb" + }, + "cdp_id": "1228", + "depositor": "kava1u2vfd56wfs3d7gq25dn5x5z2zhmwzsmdadut45" + }, + { + "amount": { + "amount": "499980824210", + "denom": "bnb" + }, + "cdp_id": "1229", + "depositor": "kava1as5f599ltjc9uy5dpne9pkhzuylcdhsj7sa2du" + }, + { + "amount": { + "amount": "509998000", + "denom": "bnb" + }, + "cdp_id": "1231", + "depositor": "kava1p42hz5v9330x7hrx07xgl5g7tw55vgkm2mdk9p" + }, + { + "amount": { + "amount": "6509723000", + "denom": "bnb" + }, + "cdp_id": "1232", + "depositor": "kava1gpqjt96w5kef6u7almss4h378tdjar0grnngd8" + }, + { + "amount": { + "amount": "100000000", + "denom": "bnb" + }, + "cdp_id": "1238", + "depositor": "kava13d3nklvf22whykz5a8vt8qlj66029gpwqcmj69" + }, + { + "amount": { + "amount": "44070000000", + "denom": "bnb" + }, + "cdp_id": "1239", + "depositor": "kava1de5gcyqfjldkmsmafa23zversglczynan76h6p" + }, + { + "amount": { + "amount": "5624859500", + "denom": "bnb" + }, + "cdp_id": "1244", + "depositor": "kava1r7slfdygrmkyhd52q7gdq2c2n6aysk97w3xkve" + }, + { + "amount": { + "amount": "104711500", + "denom": "bnb" + }, + "cdp_id": "1246", + "depositor": "kava1scykt2dj20ysamp2ysrtuymxnt4xlthj0tk3v6" + }, + { + "amount": { + "amount": "79961500", + "denom": "bnb" + }, + "cdp_id": "1247", + "depositor": "kava1pphezceeqfag2x64g4sgmun8k2y0a2tvd6z2v6" + }, + { + "amount": { + "amount": "210000000000", + "denom": "bnb" + }, + "cdp_id": "1251", + "depositor": "kava15whxe2p0exnpw5wze2f3kllwhhqlq23054knmc" + }, + { + "amount": { + "amount": "99999000", + "denom": "bnb" + }, + "cdp_id": "1252", + "depositor": "kava19fl64dfhnmzs6vkc3al60swdps7qlkfd57sk3t" + }, + { + "amount": { + "amount": "177314529", + "denom": "bnb" + }, + "cdp_id": "1254", + "depositor": "kava1696468hu2u839dh8zarjyqw6k835yrttvr3ngx" + }, + { + "amount": { + "amount": "67342419", + "denom": "bnb" + }, + "cdp_id": "1255", + "depositor": "kava17wpx9k6zhmlryp6y9ylj2gameuvn8gjcx2tvgj" + }, + { + "amount": { + "amount": "255146000", + "denom": "bnb" + }, + "cdp_id": "1257", + "depositor": "kava1584lapcfysyezhg80t8ptajctr8kaq7mtc4e0q" + }, + { + "amount": { + "amount": "499999000", + "denom": "bnb" + }, + "cdp_id": "1258", + "depositor": "kava1vmressd4gu3lmg9tfwe9uw0dy4gy5egsrcuqxj" + }, + { + "amount": { + "amount": "166384750", + "denom": "bnb" + }, + "cdp_id": "1259", + "depositor": "kava1gk63zjv594rmmdyecuegfr83nzw5ekwvsamzu2" + }, + { + "amount": { + "amount": "143939996000", + "denom": "bnb" + }, + "cdp_id": "1260", + "depositor": "kava135jlpa753t434kxf4hyl4h3jas6hyc3uc0fc4c" + }, + { + "amount": { + "amount": "100003609", + "denom": "bnb" + }, + "cdp_id": "1261", + "depositor": "kava1clqkqzccvn25cpd2e8ggh2upzh6qrh67ltl3pg" + }, + { + "amount": { + "amount": "2001188032", + "denom": "bnb" + }, + "cdp_id": "1263", + "depositor": "kava17d6e7gar8qztzrdm5vmg2x3e5rc4srklpv02x0" + }, + { + "amount": { + "amount": "18359781094", + "denom": "bnb" + }, + "cdp_id": "1265", + "depositor": "kava15adrjuvyk62x0klyukaums95frw5usm4v6daj9" + }, + { + "amount": { + "amount": "99999000", + "denom": "bnb" + }, + "cdp_id": "1267", + "depositor": "kava13trsjpgjx4jvm6j96zxa8u4t9nf5mdddp5pwd7" + }, + { + "amount": { + "amount": "378586779", + "denom": "bnb" + }, + "cdp_id": "1268", + "depositor": "kava1j4m60f93t0fcyhf2lwvkhm2p2aswafjswv0xhd" + }, + { + "amount": { + "amount": "3059884500", + "denom": "bnb" + }, + "cdp_id": "1270", + "depositor": "kava14pdjqq4v30rsndsndzyvqndqvzwwj3lt3wj066" + }, + { + "amount": { + "amount": "4956406298", + "denom": "bnb" + }, + "cdp_id": "1274", + "depositor": "kava1ku2nd6z0c3nst0z8xq8er75alrph6t0tfuyylv" + }, + { + "amount": { + "amount": "4999961500", + "denom": "bnb" + }, + "cdp_id": "1276", + "depositor": "kava1u8nnfm338cu7vq7pkt0hnuqdh6w255pg6fse7q" + }, + { + "amount": { + "amount": "89918663", + "denom": "bnb" + }, + "cdp_id": "1277", + "depositor": "kava1hhppzv49v3ykpw94euytxg7xp22wddmnfaas8f" + }, + { + "amount": { + "amount": "1736726669", + "denom": "bnb" + }, + "cdp_id": "1278", + "depositor": "kava1zmmrqremnqj4j8y6cm8cg3av6chp5f5tpyxuwq" + }, + { + "amount": { + "amount": "95991124", + "denom": "bnb" + }, + "cdp_id": "1279", + "depositor": "kava1rm4kcra7njawz0cm8uamxddu2n4uelykq5lv8r" + }, + { + "amount": { + "amount": "1589999000", + "denom": "bnb" + }, + "cdp_id": "1281", + "depositor": "kava1xu4ft9ul3jh9khrjt69rhmt6pfd3jtea0wstv8" + }, + { + "amount": { + "amount": "593041575", + "denom": "bnb" + }, + "cdp_id": "1282", + "depositor": "kava174pvmplhj38tjy45qqlfhzmkyldljg6r755dna" + }, + { + "amount": { + "amount": "800000000", + "denom": "bnb" + }, + "cdp_id": "1283", + "depositor": "kava1yn80gd43m0m329gsxwml3qcmu07gh4qczfufmn" + }, + { + "amount": { + "amount": "103128000", + "denom": "bnb" + }, + "cdp_id": "1286", + "depositor": "kava1zyrpqcgl3aeyp2vn0e5y43sskwvqjlqazlzgcv" + }, + { + "amount": { + "amount": "69999000", + "denom": "bnb" + }, + "cdp_id": "1287", + "depositor": "kava1pz23zc6stea4ctl5jrclxpzzq3ftfgxslxvlqg" + }, + { + "amount": { + "amount": "499961500", + "denom": "bnb" + }, + "cdp_id": "1289", + "depositor": "kava1yf7s5puv3fwv0jlxqk45x5mzl893ellcyly4wd" + }, + { + "amount": { + "amount": "99961500", + "denom": "bnb" + }, + "cdp_id": "1292", + "depositor": "kava1uqm720kpl45qhvkttz5ul46qzgch7ltg0wc32j" + }, + { + "amount": { + "amount": "5249999000", + "denom": "bnb" + }, + "cdp_id": "1297", + "depositor": "kava12649nuzxgmd374s9umfq36ty20e8exqycznuuv" + }, + { + "amount": { + "amount": "92209000", + "denom": "bnb" + }, + "cdp_id": "1301", + "depositor": "kava1unhe2nyn6klp0q2lucy7d02h0ln2etvcs624ha" + }, + { + "amount": { + "amount": "101191500", + "denom": "bnb" + }, + "cdp_id": "1302", + "depositor": "kava1sfzcujgrda8psrhrwmnsyr50zla3eht0fkatuv" + }, + { + "amount": { + "amount": "81294500", + "denom": "bnb" + }, + "cdp_id": "1305", + "depositor": "kava1luqjeckzr9ylzj2jpl2gtaxlr2j7d7sn2ssznf" + }, + { + "amount": { + "amount": "98723000", + "denom": "bnb" + }, + "cdp_id": "1306", + "depositor": "kava1cx4d9mz9vyt7806wqqm3q7nzj4pd4nzvn8v25v" + }, + { + "amount": { + "amount": "257330113", + "denom": "bnb" + }, + "cdp_id": "1317", + "depositor": "kava10aan0klyyxuvv5tdgrghf85agzq76uy0n2a7l5" + }, + { + "amount": { + "amount": "118659605", + "denom": "bnb" + }, + "cdp_id": "1319", + "depositor": "kava1969cxuzxhdsk8cn0anspwdlk2l5scrm0dqlhpy" + }, + { + "amount": { + "amount": "771678715", + "denom": "bnb" + }, + "cdp_id": "1320", + "depositor": "kava1hyeh8p3gk5y4s55eazr9r0fd4yjf3fkgfgfj2a" + }, + { + "amount": { + "amount": "109998000", + "denom": "bnb" + }, + "cdp_id": "1322", + "depositor": "kava1kp4x2u06esxzjkp3fhkwf6ap6g0ne4348z8vj0" + }, + { + "amount": { + "amount": "1030250000000", + "denom": "bnb" + }, + "cdp_id": "1323", + "depositor": "kava1lrrzm6celm0hp9nkm27etlyq0tp74szn2wdfg8" + }, + { + "amount": { + "amount": "137488944", + "denom": "bnb" + }, + "cdp_id": "1324", + "depositor": "kava1hfp6htzwlryl3kpuc2cd3wu2my47pr3t7ndj2k" + }, + { + "amount": { + "amount": "98043000", + "denom": "bnb" + }, + "cdp_id": "1328", + "depositor": "kava17n2afhpwfr8avv47ga07sdfw7vl46r2y5fz5zj" + }, + { + "amount": { + "amount": "185530000", + "denom": "bnb" + }, + "cdp_id": "1329", + "depositor": "kava1x8cy4tfcxzywqwenttjswlv6x8swhc6hz2xfxq" + }, + { + "amount": { + "amount": "313356363", + "denom": "bnb" + }, + "cdp_id": "1340", + "depositor": "kava180925d4xdvu7xzrsnxajylj72zccxunzjnmsem" + }, + { + "amount": { + "amount": "110000000", + "denom": "bnb" + }, + "cdp_id": "1345", + "depositor": "kava1xg0ktvzyqq7z6nx57e4yhfzsxxwh9nft5xyh8j" + }, + { + "amount": { + "amount": "376061500", + "denom": "bnb" + }, + "cdp_id": "1349", + "depositor": "kava1puk39x7klt3yk3mc8p6s4rzx55m2qneck39dny" + }, + { + "amount": { + "amount": "108163287", + "denom": "bnb" + }, + "cdp_id": "1351", + "depositor": "kava1m58kxv9ecjgz4nfn2hjfsqd7m0ymk2rn0u9d5j" + }, + { + "amount": { + "amount": "509465880", + "denom": "bnb" + }, + "cdp_id": "1352", + "depositor": "kava1w2h89j6vp4520nhl3ap23xxvwv65vtj07nh5kt" + }, + { + "amount": { + "amount": "68051902", + "denom": "bnb" + }, + "cdp_id": "1355", + "depositor": "kava1v4cpsf2tzygdzvmyqza9fz5mglc0h6fmvcn4ad" + }, + { + "amount": { + "amount": "59999000", + "denom": "bnb" + }, + "cdp_id": "1357", + "depositor": "kava1vxycqlk4wjgw759jy85w3fd9ggv02sy0jnr5xl" + }, + { + "amount": { + "amount": "99999000", + "denom": "bnb" + }, + "cdp_id": "1358", + "depositor": "kava1na8wk7yu8tp7zafyhaujwywv8gvz0vn8g7ryx8" + }, + { + "amount": { + "amount": "319997000", + "denom": "bnb" + }, + "cdp_id": "1359", + "depositor": "kava1se0fn725w2tk2rvqun02wnc70jmaret6xt0ymz" + }, + { + "amount": { + "amount": "3209723000", + "denom": "bnb" + }, + "cdp_id": "1360", + "depositor": "kava1hu4d2xcerckx35pl4cpkl55guhs06sgcja0er0" + }, + { + "amount": { + "amount": "89209600", + "denom": "bnb" + }, + "cdp_id": "1361", + "depositor": "kava1t0l6gx3tz5jeqdqzgkl7xcy4arhn2cskgfurgc" + }, + { + "amount": { + "amount": "147617845", + "denom": "bnb" + }, + "cdp_id": "1363", + "depositor": "kava1qq9ustlc0nv4aew275w93g4qy5zahqgxf5mwv9" + }, + { + "amount": { + "amount": "550364145", + "denom": "bnb" + }, + "cdp_id": "1364", + "depositor": "kava1wk6swqywa5esnnp0wyvhxy7j72rt9gn4t9ma8r" + }, + { + "amount": { + "amount": "230000000", + "denom": "bnb" + }, + "cdp_id": "1372", + "depositor": "kava1v9yhqm95fzhxj47gn68f6vxmjvt5gy9csgzuw8" + }, + { + "amount": { + "amount": "999961500", + "denom": "bnb" + }, + "cdp_id": "1380", + "depositor": "kava1730sscuel2mu4el3y7hq7ee5u4m84rjlwr5msw" + }, + { + "amount": { + "amount": "112246039", + "denom": "bnb" + }, + "cdp_id": "1383", + "depositor": "kava1tanhljwuka9lurdvxwzp3y625pt8zxdjaxqf8a" + }, + { + "amount": { + "amount": "102627192", + "denom": "bnb" + }, + "cdp_id": "1384", + "depositor": "kava1f7dcpepswwk0l77rwmgatdncdpw0drruaaagp7" + }, + { + "amount": { + "amount": "499799723000", + "denom": "bnb" + }, + "cdp_id": "1399", + "depositor": "kava1snaq99cvtjzcu9uagtw5j7guu62gpr75q0cvh5" + }, + { + "amount": { + "amount": "63640000", + "denom": "bnb" + }, + "cdp_id": "1400", + "depositor": "kava1y5gg3wpwymdz90c9crz8jnar0clzw79znl7rmg" + }, + { + "amount": { + "amount": "150000000", + "denom": "bnb" + }, + "cdp_id": "1403", + "depositor": "kava1fyw7yxxjw535cudc270wcj3ea3fyn8p9pu6qvd" + }, + { + "amount": { + "amount": "2099998000", + "denom": "bnb" + }, + "cdp_id": "1410", + "depositor": "kava1n20rxrt3a4mlslnhjk8n4edlh7fpzy438cv48m" + }, + { + "amount": { + "amount": "249999000", + "denom": "bnb" + }, + "cdp_id": "1413", + "depositor": "kava14cgufq9dxenj2wpvu6f28w2pvgz472zcfd54jd" + }, + { + "amount": { + "amount": "4548884643", + "denom": "bnb" + }, + "cdp_id": "1414", + "depositor": "kava16cg0hgegyy4z6kph2zmp92vklrjex4veta96s0" + }, + { + "amount": { + "amount": "94998000", + "denom": "bnb" + }, + "cdp_id": "1415", + "depositor": "kava1e726rq39ue8yk9kr67lpv2cfd58dyfylwtqxfn" + }, + { + "amount": { + "amount": "211550255", + "denom": "bnb" + }, + "cdp_id": "1420", + "depositor": "kava1fdzpv9rrn8gvsxg8adp2kwyqnwuyxezjy742j2" + }, + { + "amount": { + "amount": "11435775702", + "denom": "bnb" + }, + "cdp_id": "1429", + "depositor": "kava1hfmlqt5qxatfzh3jnyx55ztl050ev7u6l9qefq" + }, + { + "amount": { + "amount": "14319113251", + "denom": "bnb" + }, + "cdp_id": "1440", + "depositor": "kava1m3r9maghhlky9sdwrgt6z532r4sskz8399zvr9" + }, + { + "amount": { + "amount": "4767052472", + "denom": "bnb" + }, + "cdp_id": "1445", + "depositor": "kava13yncpezqz9j5gyl64l5f2rd7k7dtr2eaa0gtwg" + }, + { + "amount": { + "amount": "18754089441", + "denom": "bnb" + }, + "cdp_id": "1449", + "depositor": "kava1mwc52eye7u8n4fqllt5jzp762clqgkzd655mxx" + }, + { + "amount": { + "amount": "136124159", + "denom": "bnb" + }, + "cdp_id": "1454", + "depositor": "kava1vd5fqxnnc0e7p0jr8sggwd4sfcz78ahtswu2ve" + }, + { + "amount": { + "amount": "1000000000", + "denom": "bnb" + }, + "cdp_id": "1462", + "depositor": "kava1c547d5ewazfzv0d7xdk03yfg8fvrpm07wn00e0" + }, + { + "amount": { + "amount": "15000000000", + "denom": "bnb" + }, + "cdp_id": "1476", + "depositor": "kava1e2pmq54dyq8xzdq6n9dnquvt0ux3mu2n56wqgg" + }, + { + "amount": { + "amount": "900000000", + "denom": "bnb" + }, + "cdp_id": "1481", + "depositor": "kava1uy3fnhxlqnady9rfx3h9uc35xtnx0u94eh744w" + }, + { + "amount": { + "amount": "97849489", + "denom": "bnb" + }, + "cdp_id": "1487", + "depositor": "kava1td0y8y9m7tjmq59v0uykjjrpdj2mq0y5h28keu" + }, + { + "amount": { + "amount": "559315359", + "denom": "bnb" + }, + "cdp_id": "1503", + "depositor": "kava1wzegq9jk7pa8zysckmjth2wevynd2a2k0ywc35" + }, + { + "amount": { + "amount": "399768953", + "denom": "bnb" + }, + "cdp_id": "1513", + "depositor": "kava1cl2ssjt2w6jd4ur5ucwr39pecyst6h0jxh9v38" + }, + { + "amount": { + "amount": "110000000", + "denom": "bnb" + }, + "cdp_id": "1518", + "depositor": "kava18awfuum2mk0f62trzmlznw3q3qhxf9ggqf6qwf" + }, + { + "amount": { + "amount": "5000423699", + "denom": "bnb" + }, + "cdp_id": "1533", + "depositor": "kava1t2u6mhqng5tkwkvjkj8fcp7szq2lkaffydwh2j" + }, + { + "amount": { + "amount": "46289722000", + "denom": "bnb" + }, + "cdp_id": "1535", + "depositor": "kava1mwxyxveamzwkxtnwkvcftlp4ulgexx4msuyvgr" + }, + { + "amount": { + "amount": "71369000", + "denom": "bnb" + }, + "cdp_id": "1544", + "depositor": "kava1066l6vw7kycx8tmesp8y4mtmphmptc0hw88wj8" + }, + { + "amount": { + "amount": "3772564386", + "denom": "bnb" + }, + "cdp_id": "1553", + "depositor": "kava1d6lk9aug3rq6wr57rzc54vstus67amgsxvxkhv" + }, + { + "amount": { + "amount": "124769150", + "denom": "bnb" + }, + "cdp_id": "1555", + "depositor": "kava1alt4u48umfqgx6uwuhvu5qts67t78p86ejlv5y" + }, + { + "amount": { + "amount": "3999961500", + "denom": "bnb" + }, + "cdp_id": "1562", + "depositor": "kava184f7d6lwrd2esrmuvqfqrln7crv5n7vu07zq27" + }, + { + "amount": { + "amount": "5499999000", + "denom": "bnb" + }, + "cdp_id": "1567", + "depositor": "kava1p4e6fdztuwz8ukctfg7hxth0x5rump93kvy4kg" + }, + { + "amount": { + "amount": "100068357", + "denom": "bnb" + }, + "cdp_id": "1568", + "depositor": "kava1jplrqjhj2x7khpr3ppzmn202yq5exhm3hl2aj5" + }, + { + "amount": { + "amount": "999999000", + "denom": "bnb" + }, + "cdp_id": "1570", + "depositor": "kava1a5vvwsfmnehh5ng73w8v3xvhch6dm60xjzg2xf" + }, + { + "amount": { + "amount": "249999000", + "denom": "bnb" + }, + "cdp_id": "1573", + "depositor": "kava1xr2csjw6h8z4tawqeqcswvpq5p78rgpgurc20d" + }, + { + "amount": { + "amount": "198549789414", + "denom": "bnb" + }, + "cdp_id": "1575", + "depositor": "kava1rs8hkzyescwe3kqfu0dcqw2zd7td24ekywaxre" + }, + { + "amount": { + "amount": "200000000", + "denom": "bnb" + }, + "cdp_id": "1580", + "depositor": "kava1ksqqkkryqewvcddz9j02sgvnxrh75c5hg35t6e" + }, + { + "amount": { + "amount": "2000000000", + "denom": "bnb" + }, + "cdp_id": "1583", + "depositor": "kava1xwkrx4ytz6vsa5d3pc0pcsyr6twuwfdwap2vvy" + }, + { + "amount": { + "amount": "534010481", + "denom": "bnb" + }, + "cdp_id": "1584", + "depositor": "kava1pzdsm4chkg4nwvj7lxrsx20s5r4va74y6z3jzs" + }, + { + "amount": { + "amount": "1500000000", + "denom": "bnb" + }, + "cdp_id": "1585", + "depositor": "kava1vl99a0xpmm4dg6epd7snjgxpzqe4px7e3v4mel" + }, + { + "amount": { + "amount": "200000000", + "denom": "bnb" + }, + "cdp_id": "1590", + "depositor": "kava1wefhhne7mr65dr9vw0qgdp7wu22zv0j2sghd75" + }, + { + "amount": { + "amount": "700861500", + "denom": "bnb" + }, + "cdp_id": "1593", + "depositor": "kava1hqsy9e39zp2dla42cy8lj7y6ylzu8y8xjmr0wq" + }, + { + "amount": { + "amount": "100542131", + "denom": "bnb" + }, + "cdp_id": "1594", + "depositor": "kava12yhn75au348gl32u0vtcn529rxqysjlenxpx2t" + }, + { + "amount": { + "amount": "69999000", + "denom": "bnb" + }, + "cdp_id": "1596", + "depositor": "kava1lc4dwgtnaynd765zdkmn9a3p4vu2yn442u5e9n" + }, + { + "amount": { + "amount": "1229241373", + "denom": "bnb" + }, + "cdp_id": "1597", + "depositor": "kava19dtn5apvmrytsma7nmq4tqfyh8js4npv6tculu" + }, + { + "amount": { + "amount": "528561869", + "denom": "bnb" + }, + "cdp_id": "1599", + "depositor": "kava17c3w0dcyrpwemfhu25ds59vjum0d58fwxgf6h8" + }, + { + "amount": { + "amount": "817998000", + "denom": "bnb" + }, + "cdp_id": "1671", + "depositor": "kava12nwz55p7g29wn5hg44g5ljp9rrsvufdt2v0a6y" + }, + { + "amount": { + "amount": "1949999000", + "denom": "bnb" + }, + "cdp_id": "1682", + "depositor": "kava1tkz0j7v8x3qe6u8tvfda8kz00747ntgxlglzl4" + }, + { + "amount": { + "amount": "482061500", + "denom": "bnb" + }, + "cdp_id": "1689", + "depositor": "kava1sdygaq5q4mkq2gtdr2q6ex6c79lw4dn928smcd" + }, + { + "amount": { + "amount": "50984997000", + "denom": "bnb" + }, + "cdp_id": "1690", + "depositor": "kava17hgvly0hyqgdktkg7k34pqx0nst3t0rguy62ta" + }, + { + "amount": { + "amount": "15740079851", + "denom": "bnb" + }, + "cdp_id": "1696", + "depositor": "kava1qxprregw2tvclv5ecg23u8cm8vwx500aqwcp5g" + }, + { + "amount": { + "amount": "379961500", + "denom": "bnb" + }, + "cdp_id": "1697", + "depositor": "kava1qhhhgn6va38sw55p2eawyccl2ljpmk7zdlar84" + }, + { + "amount": { + "amount": "11099000000", + "denom": "bnb" + }, + "cdp_id": "1713", + "depositor": "kava1h2z0dvaapp99935p6khak42js7xychup072l0a" + }, + { + "amount": { + "amount": "2811987457763", + "denom": "bnb" + }, + "cdp_id": "1719", + "depositor": "kava1x242qk6jf2rv23ruvk6fmxp97gg2y75a9r2caq" + }, + { + "amount": { + "amount": "316999999000", + "denom": "bnb" + }, + "cdp_id": "1731", + "depositor": "kava10wyahu4d23fgtzjdxc998gn7z48lc2nte79z37" + }, + { + "amount": { + "amount": "49999860500", + "denom": "bnb" + }, + "cdp_id": "1738", + "depositor": "kava1jvxu04elz2lklea8sv36lk0x973hrwr4mu9lt2" + }, + { + "amount": { + "amount": "100000000", + "denom": "bnb" + }, + "cdp_id": "1751", + "depositor": "kava1v5jwfer6xe67yvp844paw8alj6x7w080gc8hpf" + }, + { + "amount": { + "amount": "100000000", + "denom": "bnb" + }, + "cdp_id": "1753", + "depositor": "kava14tex78srs63fk436kef8d3wct0wqjh2ttzdk8y" + }, + { + "amount": { + "amount": "500000000", + "denom": "bnb" + }, + "cdp_id": "1760", + "depositor": "kava1g9r25c4t2fcq9pett9x89758gyw3hjhydg7y5u" + }, + { + "amount": { + "amount": "159200000500", + "denom": "bnb" + }, + "cdp_id": "1761", + "depositor": "kava1ehtxa3cy5s5ulksfswx5c7umftlm0p2yrnc6vd" + }, + { + "amount": { + "amount": "99999000", + "denom": "bnb" + }, + "cdp_id": "1765", + "depositor": "kava1wnpxrmcn8nu9skukt7fzwyr98f3x059kt35v3p" + }, + { + "amount": { + "amount": "112221184", + "denom": "bnb" + }, + "cdp_id": "1769", + "depositor": "kava1h6eea690v3nug322wqjmgmrt0uxatg2zuz6tt9" + }, + { + "amount": { + "amount": "1200261500", + "denom": "bnb" + }, + "cdp_id": "1777", + "depositor": "kava16utunjj9df9p2dkahdg2hs2e0qasz4rh84lhrp" + }, + { + "amount": { + "amount": "145000000", + "denom": "bnb" + }, + "cdp_id": "1778", + "depositor": "kava1xjh3cd48kgpgmgc7n3tp08v5d3xqp6vck3drcx" + }, + { + "amount": { + "amount": "60640062996", + "denom": "bnb" + }, + "cdp_id": "1783", + "depositor": "kava1e4fl4ht4696v274pp4dzm9fkwe6f2rfqv6q6wq" + }, + { + "amount": { + "amount": "50000084500", + "denom": "bnb" + }, + "cdp_id": "1798", + "depositor": "kava1lfjqvzynrwvul3nrv8dxme3l38896nlx6f0xkw" + }, + { + "amount": { + "amount": "405861500", + "denom": "bnb" + }, + "cdp_id": "1808", + "depositor": "kava179tps3eucdmh409hsld8z3pgfq94lyr74m2jxc" + }, + { + "amount": { + "amount": "400099960500", + "denom": "bnb" + }, + "cdp_id": "1816", + "depositor": "kava1nr3a995c3ywl8d4cplczsavvtfd5qhetffypd2" + }, + { + "amount": { + "amount": "100000000", + "denom": "bnb" + }, + "cdp_id": "1817", + "depositor": "kava12ljyewdkrpnch8z4yy8wtepr2esl8e93fwc47f" + }, + { + "amount": { + "amount": "11599999000", + "denom": "bnb" + }, + "cdp_id": "1823", + "depositor": "kava13cr8f7s0zgvd0365mq6nzsegtjjpfn3t9frcgj" + }, + { + "amount": { + "amount": "99900000", + "denom": "bnb" + }, + "cdp_id": "1829", + "depositor": "kava1zhvexd6vrfh9uem3q25xmz40pje5p59uh5dc2q" + }, + { + "amount": { + "amount": "90000000000", + "denom": "bnb" + }, + "cdp_id": "1833", + "depositor": "kava1hs8f5ya5ckzxnqg5aumagml2ttkfx968h45hev" + }, + { + "amount": { + "amount": "3810764342", + "denom": "bnb" + }, + "cdp_id": "1838", + "depositor": "kava1ucek4at0fx5pzlvraymv773shy36qsdw5w035c" + }, + { + "amount": { + "amount": "281159211", + "denom": "bnb" + }, + "cdp_id": "1843", + "depositor": "kava1j0yxk0dhfhfcyppcadt32h5jcf2pvncuz833q8" + }, + { + "amount": { + "amount": "31089999000", + "denom": "bnb" + }, + "cdp_id": "1849", + "depositor": "kava19p7kkswphk6qv5ymvj5385aq7dc7gxpzsgaa0r" + }, + { + "amount": { + "amount": "355000000", + "denom": "bnb" + }, + "cdp_id": "1850", + "depositor": "kava1cn0chmv0dt8vg9xrhj0jadc9yqx203cj3s2c9q" + }, + { + "amount": { + "amount": "5399785500", + "denom": "bnb" + }, + "cdp_id": "1851", + "depositor": "kava1rle08y653c80s9rwmpuxq9nyq5lg9c47l2m4qs" + }, + { + "amount": { + "amount": "39944954979", + "denom": "bnb" + }, + "cdp_id": "1852", + "depositor": "kava1zrthvpd9rjmyapya6xxf2ywrs4h3ugfmfw4rzu" + }, + { + "amount": { + "amount": "150924040934", + "denom": "bnb" + }, + "cdp_id": "1860", + "depositor": "kava17jpu5g2du2p0pmnq8meakcur6vm8rwezv4tn9z" + }, + { + "amount": { + "amount": "235274163", + "denom": "bnb" + }, + "cdp_id": "1863", + "depositor": "kava10tg5kv6rhm3h2ufavh0y3qmphvmvmejs8l53as" + }, + { + "amount": { + "amount": "99961500", + "denom": "bnb" + }, + "cdp_id": "1864", + "depositor": "kava1ch8equdqp9k8u87nvu5c86qvscv3p9n480g84s" + }, + { + "amount": { + "amount": "550000000", + "denom": "bnb" + }, + "cdp_id": "1865", + "depositor": "kava1lm5pc2kc4zjd3gyycm9zgjv3pcfg64ld39lgp6" + }, + { + "amount": { + "amount": "312459006", + "denom": "bnb" + }, + "cdp_id": "1867", + "depositor": "kava1chk4a3v96nhc5msc5f84f66ulujz7xdz9fh367" + }, + { + "amount": { + "amount": "200000000", + "denom": "bnb" + }, + "cdp_id": "1871", + "depositor": "kava1dz5zhsa0uxw62y06mwmaazgkhgq49e7sun6nf3" + }, + { + "amount": { + "amount": "200000000", + "denom": "bnb" + }, + "cdp_id": "1872", + "depositor": "kava1ha8cwpay5l293clga0sy0ersm8tqmv0gfgaejc" + }, + { + "amount": { + "amount": "119723000", + "denom": "bnb" + }, + "cdp_id": "1878", + "depositor": "kava1p45l37x9k3dsn8wuf90wcqxg8498y3ha54ju9a" + }, + { + "amount": { + "amount": "900000000", + "denom": "bnb" + }, + "cdp_id": "1881", + "depositor": "kava1u0h3m6s9cn4t7lcemt5yplz2r5f8pvt78t300w" + }, + { + "amount": { + "amount": "999999000", + "denom": "bnb" + }, + "cdp_id": "1883", + "depositor": "kava1peyjt72c2dk4ge7gavl56amvqxzukjyu7qth3s" + }, + { + "amount": { + "amount": "200000000", + "denom": "bnb" + }, + "cdp_id": "1891", + "depositor": "kava1etzj0qsu36dfyxa44r2pwz6am5un99ge7ee2aq" + }, + { + "amount": { + "amount": "249571613", + "denom": "bnb" + }, + "cdp_id": "1895", + "depositor": "kava1lf86aj2akcrt5ehtvfgnhlrlj442z676usk9ly" + }, + { + "amount": { + "amount": "147998000", + "denom": "bnb" + }, + "cdp_id": "1896", + "depositor": "kava1t4ctv6vzg77qwrprdzjs22rxcg8wc3usscjvnx" + }, + { + "amount": { + "amount": "2809484751", + "denom": "bnb" + }, + "cdp_id": "1897", + "depositor": "kava1efqg07y6eyrt3x80fcsdv99kj2ezya7pntjutl" + }, + { + "amount": { + "amount": "899999000", + "denom": "bnb" + }, + "cdp_id": "1901", + "depositor": "kava10fu8zc5qtw2wa50z244cnlxxa3pjs8el0hc8p0" + }, + { + "amount": { + "amount": "199999000", + "denom": "bnb" + }, + "cdp_id": "1916", + "depositor": "kava1xcku3nqxm5jt7fhgrk9pvpdqqfjkxlwx2m8aka" + }, + { + "amount": { + "amount": "2144242904", + "denom": "bnb" + }, + "cdp_id": "1917", + "depositor": "kava1p063qu3kh40ruw7ytwmayj7q5lreaq9skyett9" + }, + { + "amount": { + "amount": "3488776197", + "denom": "bnb" + }, + "cdp_id": "1918", + "depositor": "kava1p2kvztny6e4ffttdp2kmwlzg33zpu8n4cdza0v" + }, + { + "amount": { + "amount": "1002498", + "denom": "btcb" + }, + "cdp_id": "1365", + "depositor": "kava1gzc54u4p67hh9r4m9vcml3ke9fc29tplvvaev3" + }, + { + "amount": { + "amount": "7929738", + "denom": "btcb" + }, + "cdp_id": "1370", + "depositor": "kava1r7uckqzflqdqcwllh3ty36qvzl0z7utv5ujh3l" + }, + { + "amount": { + "amount": "279998", + "denom": "btcb" + }, + "cdp_id": "1374", + "depositor": "kava1vlpsrmdyuywvaqrv7rx6xga224sqfwz3fyfhwq" + }, + { + "amount": { + "amount": "1208494457", + "denom": "btcb" + }, + "cdp_id": "1376", + "depositor": "kava1wjjg0mvsfgnskjj7qq28uaxqwq5h38q6nh5ah8" + }, + { + "amount": { + "amount": "9999998", + "denom": "btcb" + }, + "cdp_id": "1388", + "depositor": "kava179ahnk902wgm7qzr66t5ga0a8euc28ce703jy3" + }, + { + "amount": { + "amount": "35097117", + "denom": "btcb" + }, + "cdp_id": "1396", + "depositor": "kava1acqutt8qfe66c0nnhlzl7rmadfnuxnuaetehfh" + }, + { + "amount": { + "amount": "10086310", + "denom": "btcb" + }, + "cdp_id": "1401", + "depositor": "kava1tzzdns8zkl0qptywnpr27eh0evj9zu45pc8f0g" + }, + { + "amount": { + "amount": "91840786", + "denom": "btcb" + }, + "cdp_id": "1406", + "depositor": "kava1vrc7zv2epn6es9whxycava8uwta9ncax8wuw6l" + }, + { + "amount": { + "amount": "131316", + "denom": "btcb" + }, + "cdp_id": "1408", + "depositor": "kava18a8gwg9kz0efhww629h99cclwyywrwrf97l669" + }, + { + "amount": { + "amount": "19999994", + "denom": "btcb" + }, + "cdp_id": "1409", + "depositor": "kava15jtcnhucatrg8z70s5huxpyhnwf2klupv6xqyq" + }, + { + "amount": { + "amount": "109058", + "denom": "btcb" + }, + "cdp_id": "1418", + "depositor": "kava1w4umquan7w2v3n3enh6ap854vk4a58kftnq4au" + }, + { + "amount": { + "amount": "282155", + "denom": "btcb" + }, + "cdp_id": "1419", + "depositor": "kava1e726rq39ue8yk9kr67lpv2cfd58dyfylwtqxfn" + }, + { + "amount": { + "amount": "80948774", + "denom": "btcb" + }, + "cdp_id": "1422", + "depositor": "kava1rea6zxqq78klh7uhf78juqp9nmtl53j7hsnquk" + }, + { + "amount": { + "amount": "36567486", + "denom": "btcb" + }, + "cdp_id": "1423", + "depositor": "kava1lmdqakjz5p7gjw3q7333kkgc2xje4d6zzu544k" + }, + { + "amount": { + "amount": "36768000", + "denom": "btcb" + }, + "cdp_id": "1424", + "depositor": "kava10l6gr3u8xqfd8jps724n4hkhd92fh9rugyx2n7" + }, + { + "amount": { + "amount": "2499996", + "denom": "btcb" + }, + "cdp_id": "1426", + "depositor": "kava1naekqn8vfcxdrge0qmajf0t8uatamf6lhd4w6x" + }, + { + "amount": { + "amount": "449444", + "denom": "btcb" + }, + "cdp_id": "1450", + "depositor": "kava12ltf567h50jf3juw3a9m996fwe5jyma676l0gw" + }, + { + "amount": { + "amount": "6630179", + "denom": "btcb" + }, + "cdp_id": "1464", + "depositor": "kava1ttrw6gxz9nz49gse9v0tqqa2u97s34yx4shl55" + }, + { + "amount": { + "amount": "46020422", + "denom": "btcb" + }, + "cdp_id": "1473", + "depositor": "kava1h8fsy6u3hy77hn8gguh59qx9s6mn64rshfke2l" + }, + { + "amount": { + "amount": "14070705", + "denom": "btcb" + }, + "cdp_id": "1510", + "depositor": "kava182mzj3c7hg96fsaratn0wt2khgtgxgvlwhg77e" + }, + { + "amount": { + "amount": "13646103", + "denom": "btcb" + }, + "cdp_id": "1602", + "depositor": "kava127lary0erprnrv9vn3wykyt9pjm5a5tdwdnm3h" + }, + { + "amount": { + "amount": "1964000", + "denom": "btcb" + }, + "cdp_id": "1605", + "depositor": "kava13d3nklvf22whykz5a8vt8qlj66029gpwqcmj69" + }, + { + "amount": { + "amount": "151237022", + "denom": "btcb" + }, + "cdp_id": "1606", + "depositor": "kava1dpcgtp7hjvspg7nxpj7c7j25lnyyrau0g72jkd" + }, + { + "amount": { + "amount": "499999990", + "denom": "btcb" + }, + "cdp_id": "1607", + "depositor": "kava1mz2vfw29fzkg4yj9wfh99nkgx46unhrxtyxqhc" + }, + { + "amount": { + "amount": "39761118", + "denom": "btcb" + }, + "cdp_id": "1608", + "depositor": "kava1g74prc3x3ke2250ndr8ndpkceqvzwdqzq8ddt7" + }, + { + "amount": { + "amount": "7486653", + "denom": "btcb" + }, + "cdp_id": "1609", + "depositor": "kava1y39ev0vqwnzqr3uhm26lp0ywwjjcfsf4ylvtmy" + }, + { + "amount": { + "amount": "499999998", + "denom": "btcb" + }, + "cdp_id": "1610", + "depositor": "kava1mgw47h20dkwqv7n2u8qg9ujds208x6mrg2zza0" + }, + { + "amount": { + "amount": "109999998", + "denom": "btcb" + }, + "cdp_id": "1611", + "depositor": "kava1y78l0cnun58rqlkj60w2wvf7a6lsc3exs5tpaj" + }, + { + "amount": { + "amount": "8920460438", + "denom": "btcb" + }, + "cdp_id": "1612", + "depositor": "kava10hczxv0p3eadcwgt5u79yhahsyuw98u26qan50" + }, + { + "amount": { + "amount": "99999998", + "denom": "btcb" + }, + "cdp_id": "1613", + "depositor": "kava1n7rtcw75duvqgaylyq0lr3337dyxzcg0m3hdg0" + }, + { + "amount": { + "amount": "5332145883", + "denom": "btcb" + }, + "cdp_id": "1614", + "depositor": "kava1as5f599ltjc9uy5dpne9pkhzuylcdhsj7sa2du" + }, + { + "amount": { + "amount": "6416466", + "denom": "btcb" + }, + "cdp_id": "1617", + "depositor": "kava1zuslhtgj5r8n95k833w5lttnjzuxcpjy7ql3c5" + }, + { + "amount": { + "amount": "1098743033", + "denom": "btcb" + }, + "cdp_id": "1618", + "depositor": "kava19fqslxa2fv5wfdwh6gvpp2jwkuzkvcwv40qz89" + }, + { + "amount": { + "amount": "999999656", + "denom": "btcb" + }, + "cdp_id": "1619", + "depositor": "kava1a4n95kh4exg0krr4vqwdnuf2sm2zzs9ape904x" + }, + { + "amount": { + "amount": "230418504", + "denom": "btcb" + }, + "cdp_id": "1623", + "depositor": "kava1un2a96zhymexgdx9ujeldm2a6te9ar66n2en78" + }, + { + "amount": { + "amount": "1089952", + "denom": "btcb" + }, + "cdp_id": "1624", + "depositor": "kava1c5lzj543l3xlz8s4s03phkkm4p0g6qg570vjys" + }, + { + "amount": { + "amount": "49999998", + "denom": "btcb" + }, + "cdp_id": "1626", + "depositor": "kava10lhnlwlek6yg5n734jn8qukur2kjjhcw09xagl" + }, + { + "amount": { + "amount": "11906816", + "denom": "btcb" + }, + "cdp_id": "1627", + "depositor": "kava19kncpd7la86z27snj6996u3ds5mtcmc5n864vx" + }, + { + "amount": { + "amount": "73425973", + "denom": "btcb" + }, + "cdp_id": "1628", + "depositor": "kava1lfdxw8lg7m4zgx5f2t3szkarypcytahfnl26n4" + }, + { + "amount": { + "amount": "27500144", + "denom": "btcb" + }, + "cdp_id": "1629", + "depositor": "kava1a7vmnk0qfwuxq0jsek3hr798xutu24ga78s3ys" + }, + { + "amount": { + "amount": "60000476", + "denom": "btcb" + }, + "cdp_id": "1631", + "depositor": "kava1tnf0zwaqx76lkpaj0un36kvwhver8dmynvr6zs" + }, + { + "amount": { + "amount": "1087721334", + "denom": "btcb" + }, + "cdp_id": "1632", + "depositor": "kava1z9v59sdu65z4hssvhhhpnw0pz9p8y3kfgh0h3p" + }, + { + "amount": { + "amount": "39842084", + "denom": "btcb" + }, + "cdp_id": "1634", + "depositor": "kava1zdtnnt6e6n949h39eskp3m3jnmzsrrda9wfl7a" + }, + { + "amount": { + "amount": "500043304", + "denom": "btcb" + }, + "cdp_id": "1636", + "depositor": "kava15fcxcndmrhagc9zxt2jj5aapavens36tm9z7wr" + }, + { + "amount": { + "amount": "13753465", + "denom": "btcb" + }, + "cdp_id": "1637", + "depositor": "kava1drk0qa554p4r9t4vw20sqn84m9xz7dp2gr0kfy" + }, + { + "amount": { + "amount": "250275549", + "denom": "btcb" + }, + "cdp_id": "1638", + "depositor": "kava1kfrjwuur93wthdwc6kpf36lwftdzz22wxe5gae" + }, + { + "amount": { + "amount": "100009828", + "denom": "btcb" + }, + "cdp_id": "1639", + "depositor": "kava1y56rm72h5nm6psg2k7mxx2gjtldyme2wyt2nds" + }, + { + "amount": { + "amount": "33683436", + "denom": "btcb" + }, + "cdp_id": "1641", + "depositor": "kava1zaq2qevfefffrps03q7y4cky9sh5frtdjv65ug" + }, + { + "amount": { + "amount": "13212486", + "denom": "btcb" + }, + "cdp_id": "1642", + "depositor": "kava1z0u0efzn8llallan08kenpuj262etz9392phf4" + }, + { + "amount": { + "amount": "6001646", + "denom": "btcb" + }, + "cdp_id": "1643", + "depositor": "kava12e7ryh3z4034zd398lwudmyvkm7hngy5xs3r4m" + }, + { + "amount": { + "amount": "21736534", + "denom": "btcb" + }, + "cdp_id": "1653", + "depositor": "kava1fymnm880d4m03276vwwlm4xwtsswyqq07jg53s" + }, + { + "amount": { + "amount": "5752908", + "denom": "btcb" + }, + "cdp_id": "1657", + "depositor": "kava1n7lp6a9fjc7qt0a6r2792kwcd2hghtuaul7x0w" + }, + { + "amount": { + "amount": "50000658", + "denom": "btcb" + }, + "cdp_id": "1658", + "depositor": "kava176nfnxq2325z72jmxragelpx2jx3fme4g796pd" + }, + { + "amount": { + "amount": "6454498", + "denom": "btcb" + }, + "cdp_id": "1660", + "depositor": "kava12ghgptqj954d7gr4uh0z5qesxaz3nffhkcam6r" + }, + { + "amount": { + "amount": "80089011", + "denom": "btcb" + }, + "cdp_id": "1661", + "depositor": "kava1mgwduvsvt00q7ksxps3zl0945dsh3v4nz9c4rd" + }, + { + "amount": { + "amount": "493700908", + "denom": "btcb" + }, + "cdp_id": "1662", + "depositor": "kava1gr8e5w5n804gn3ypvvgdqx6535d6ukmmxcqps7" + }, + { + "amount": { + "amount": "149828", + "denom": "btcb" + }, + "cdp_id": "1663", + "depositor": "kava1cekgrewfz3m0pq650zkr86pdam7zxvl2pcesnh" + }, + { + "amount": { + "amount": "3764647", + "denom": "btcb" + }, + "cdp_id": "1668", + "depositor": "kava1fpsxfx5wql5pcmmdewyy3uas5glgx899h0dcv5" + }, + { + "amount": { + "amount": "181318", + "denom": "btcb" + }, + "cdp_id": "1670", + "depositor": "kava18w6c7edz8n4testgwprr9wywp9q0lxp9sa4c26" + }, + { + "amount": { + "amount": "1000480", + "denom": "btcb" + }, + "cdp_id": "1672", + "depositor": "kava1c0xa226fh8e94k6lpsr890aw82g2zw3fq6q8r5" + }, + { + "amount": { + "amount": "6399028", + "denom": "btcb" + }, + "cdp_id": "1675", + "depositor": "kava1ne7zl2v8ag6pnrnk5rwf6atdu9tw3pers3dv63" + }, + { + "amount": { + "amount": "21538754", + "denom": "btcb" + }, + "cdp_id": "1676", + "depositor": "kava1ghhk6fd4xtvxxu4v230x4acj27c2mkxe2tu7qm" + }, + { + "amount": { + "amount": "103488267", + "denom": "btcb" + }, + "cdp_id": "1677", + "depositor": "kava19pfgjj5sp5vwa5gny0yqxp7v0g9tkd7h3j36w3" + }, + { + "amount": { + "amount": "159996", + "denom": "btcb" + }, + "cdp_id": "1678", + "depositor": "kava1607mgduk5yuqsg7kyjd25jhuxk5xcyl6ar5qdm" + }, + { + "amount": { + "amount": "258998", + "denom": "btcb" + }, + "cdp_id": "1681", + "depositor": "kava126wg3hfgrxspmtupvyqvall5g75xr7fmxdssen" + }, + { + "amount": { + "amount": "27073859", + "denom": "btcb" + }, + "cdp_id": "1683", + "depositor": "kava1l22dc2vjgrgwl73ef6rl6zp3uwr007ftnknpaw" + }, + { + "amount": { + "amount": "51765395", + "denom": "btcb" + }, + "cdp_id": "1686", + "depositor": "kava13cr8f7s0zgvd0365mq6nzsegtjjpfn3t9frcgj" + }, + { + "amount": { + "amount": "149852660", + "denom": "btcb" + }, + "cdp_id": "1687", + "depositor": "kava1pvc7dsu4hd3l2ph4t3nlv6gs8e43ktelagwamy" + }, + { + "amount": { + "amount": "220764413", + "denom": "btcb" + }, + "cdp_id": "1691", + "depositor": "kava1mwxyxveamzwkxtnwkvcftlp4ulgexx4msuyvgr" + }, + { + "amount": { + "amount": "159676", + "denom": "btcb" + }, + "cdp_id": "1692", + "depositor": "kava1zcamsjaf57tx3q79yl4e30knvl0gyckm0qpk7p" + }, + { + "amount": { + "amount": "256799913", + "denom": "btcb" + }, + "cdp_id": "1698", + "depositor": "kava1f98urpz5jj0tfhm0dy6dguk8qp4fq8yr7g0fyq" + }, + { + "amount": { + "amount": "199999998", + "denom": "btcb" + }, + "cdp_id": "1703", + "depositor": "kava1ygqcu6c6jsc443apwnad4ck0rrgpcv7hfqtsd8" + }, + { + "amount": { + "amount": "445273136", + "denom": "btcb" + }, + "cdp_id": "1705", + "depositor": "kava1yc7r3qfqxlds6aw6p9egy42vn8n8wu5hd0ksvm" + }, + { + "amount": { + "amount": "1300499676", + "denom": "btcb" + }, + "cdp_id": "1709", + "depositor": "kava1tstf3u4cw7u4xyu7wxdrnmrpvvmfamq3twcj7f" + }, + { + "amount": { + "amount": "499999933", + "denom": "btcb" + }, + "cdp_id": "1710", + "depositor": "kava165p5a7rjjzj4hjn80w3nwjr8e7kglm42xgy0w2" + }, + { + "amount": { + "amount": "20989666", + "denom": "btcb" + }, + "cdp_id": "1714", + "depositor": "kava1mj0qe9u9ztfzhnk4xzm0wu37g0m4npaa9lsjgx" + }, + { + "amount": { + "amount": "59999998", + "denom": "btcb" + }, + "cdp_id": "1716", + "depositor": "kava1qm6gheafpg68x5z24gmuknn4l6492q7gm0l9d7" + }, + { + "amount": { + "amount": "5001749700", + "denom": "btcb" + }, + "cdp_id": "1723", + "depositor": "kava10wyahu4d23fgtzjdxc998gn7z48lc2nte79z37" + }, + { + "amount": { + "amount": "40119956", + "denom": "btcb" + }, + "cdp_id": "1725", + "depositor": "kava1u205gp2kxm7kj2ta2yhtpazdyc97xgy8e3re7k" + }, + { + "amount": { + "amount": "10005083067", + "denom": "btcb" + }, + "cdp_id": "1726", + "depositor": "kava1x242qk6jf2rv23ruvk6fmxp97gg2y75a9r2caq" + }, + { + "amount": { + "amount": "57184152", + "denom": "btcb" + }, + "cdp_id": "1729", + "depositor": "kava14luenugtsynt0zme2qtp0t6sn6gq6rm83q5kag" + }, + { + "amount": { + "amount": "1236402", + "denom": "btcb" + }, + "cdp_id": "1732", + "depositor": "kava1p42hz5v9330x7hrx07xgl5g7tw55vgkm2mdk9p" + }, + { + "amount": { + "amount": "599999996", + "denom": "btcb" + }, + "cdp_id": "1735", + "depositor": "kava1fg7fcs0vupc5lyy67hatkq2nak995w3m6cvhzm" + }, + { + "amount": { + "amount": "70527822", + "denom": "btcb" + }, + "cdp_id": "1736", + "depositor": "kava1k33pgvv8fs875ht5erf4qvqpdrhtlckt2twd93" + }, + { + "amount": { + "amount": "4209963", + "denom": "btcb" + }, + "cdp_id": "1743", + "depositor": "kava1s84pcv6q8gvq262c4245yf59mg9xsdxgpngyul" + }, + { + "amount": { + "amount": "159676", + "denom": "btcb" + }, + "cdp_id": "1755", + "depositor": "kava1myxznqgakl9va5cmg946yrh3tjhnjtx40e8p0a" + }, + { + "amount": { + "amount": "120762086", + "denom": "btcb" + }, + "cdp_id": "1757", + "depositor": "kava1d9j83ll3e0jh5w8kycjcmzcm2wdy0mr353gagc" + }, + { + "amount": { + "amount": "128143145", + "denom": "btcb" + }, + "cdp_id": "1766", + "depositor": "kava1y0rytym5j70wl9cdh39e4myclgdhsctvp8mh7e" + }, + { + "amount": { + "amount": "135635914", + "denom": "btcb" + }, + "cdp_id": "1773", + "depositor": "kava1wnpxrmcn8nu9skukt7fzwyr98f3x059kt35v3p" + }, + { + "amount": { + "amount": "155264", + "denom": "btcb" + }, + "cdp_id": "1774", + "depositor": "kava1y3v4zynrf08tf2qhyv53039wcj77qagjw0w9g6" + }, + { + "amount": { + "amount": "52096485", + "denom": "btcb" + }, + "cdp_id": "1775", + "depositor": "kava1caukx55c2qcgcy94ny4y97jag8nst6nwcat06j" + }, + { + "amount": { + "amount": "5000000", + "denom": "btcb" + }, + "cdp_id": "1779", + "depositor": "kava1u746y26ykuuhurg2rzmzvpxvwvu34aw8q79ape" + }, + { + "amount": { + "amount": "598999836", + "denom": "btcb" + }, + "cdp_id": "1786", + "depositor": "kava1e37mdk9efcj2udustjdaw8acx2chcwdluwvrvs" + }, + { + "amount": { + "amount": "10848422", + "denom": "btcb" + }, + "cdp_id": "1789", + "depositor": "kava1mn72s3vjncj3gry8kwe795j4cr9rmtn90a0v5x" + }, + { + "amount": { + "amount": "32049747", + "denom": "btcb" + }, + "cdp_id": "1790", + "depositor": "kava13lmh7zyl4rtvvxyx9tszwfv4efsmfz7ahydl78" + }, + { + "amount": { + "amount": "999999838", + "denom": "btcb" + }, + "cdp_id": "1792", + "depositor": "kava15fu6ehw756hd3dyvws0xfwmrugfz8m6f5n030l" + }, + { + "amount": { + "amount": "112999678", + "denom": "btcb" + }, + "cdp_id": "1793", + "depositor": "kava1q7zew0fsez5k48elvj79dsu3k2w0k8ktej3un7" + }, + { + "amount": { + "amount": "164009342", + "denom": "btcb" + }, + "cdp_id": "1799", + "depositor": "kava1pu9g0q0ceduaq0827l0pkyjgejcfn66zg9n0rq" + }, + { + "amount": { + "amount": "5626969", + "denom": "btcb" + }, + "cdp_id": "1802", + "depositor": "kava1hqwlepgc9z8taf3hmxsfg840st6r7ptazhljme" + }, + { + "amount": { + "amount": "11999838", + "denom": "btcb" + }, + "cdp_id": "1803", + "depositor": "kava19mtegk4rd6fjfxjsmknn8862gcmfd32myj7sva" + }, + { + "amount": { + "amount": "144510928", + "denom": "btcb" + }, + "cdp_id": "1804", + "depositor": "kava1e2pmq54dyq8xzdq6n9dnquvt0ux3mu2n56wqgg" + }, + { + "amount": { + "amount": "10486328", + "denom": "btcb" + }, + "cdp_id": "1806", + "depositor": "kava1vsk22xy2sgtflh8uratwwg2ju69twmdrfwzq4x" + }, + { + "amount": { + "amount": "3690946381", + "denom": "btcb" + }, + "cdp_id": "1809", + "depositor": "kava123a8tsfuyzn285cmt600u6tpwxg7kmrgazj2hv" + }, + { + "amount": { + "amount": "531052697", + "denom": "btcb" + }, + "cdp_id": "1820", + "depositor": "kava1nr3a995c3ywl8d4cplczsavvtfd5qhetffypd2" + }, + { + "amount": { + "amount": "348971106", + "denom": "btcb" + }, + "cdp_id": "1828", + "depositor": "kava14m0dtdvs9pqeqg74g7jnxcr9tkpl4maa7r5mkv" + }, + { + "amount": { + "amount": "132743010", + "denom": "btcb" + }, + "cdp_id": "1832", + "depositor": "kava1fuwnpvv6heued9mmhlphpwgyu4fu0tzvcan9u9" + }, + { + "amount": { + "amount": "70000000", + "denom": "btcb" + }, + "cdp_id": "1835", + "depositor": "kava15adrjuvyk62x0klyukaums95frw5usm4v6daj9" + }, + { + "amount": { + "amount": "66037550", + "denom": "btcb" + }, + "cdp_id": "1840", + "depositor": "kava1x9mmnhc7rutx9jjqgv79sv7vr6xpqjymqepzlq" + }, + { + "amount": { + "amount": "49972802", + "denom": "btcb" + }, + "cdp_id": "1847", + "depositor": "kava1kk0uu0ax7ka0jle8k4shxf95ts3c7grv838jhl" + }, + { + "amount": { + "amount": "10553295", + "denom": "btcb" + }, + "cdp_id": "1853", + "depositor": "kava1zrthvpd9rjmyapya6xxf2ywrs4h3ugfmfw4rzu" + }, + { + "amount": { + "amount": "2078542", + "denom": "btcb" + }, + "cdp_id": "1854", + "depositor": "kava1e9h2eu9plxlfzdy6wfcg0477tjv7yvumutva6q" + }, + { + "amount": { + "amount": "7329143", + "denom": "btcb" + }, + "cdp_id": "1861", + "depositor": "kava1hy7prkth4zyghgm9vj5awqc7h4gn94gw9tq3rm" + }, + { + "amount": { + "amount": "499499753", + "denom": "btcb" + }, + "cdp_id": "1874", + "depositor": "kava1t7v48gu6jh26av0e089sxq4n4jxwckp8v7hp6p" + }, + { + "amount": { + "amount": "80002113", + "denom": "btcb" + }, + "cdp_id": "1875", + "depositor": "kava1rle08y653c80s9rwmpuxq9nyq5lg9c47l2m4qs" + }, + { + "amount": { + "amount": "892533097", + "denom": "btcb" + }, + "cdp_id": "1876", + "depositor": "kava1ehtxa3cy5s5ulksfswx5c7umftlm0p2yrnc6vd" + }, + { + "amount": { + "amount": "23790473", + "denom": "btcb" + }, + "cdp_id": "1879", + "depositor": "kava1wq7989t7sgn453ky9tznwtsy5m87hrt7gm8p34" + }, + { + "amount": { + "amount": "910212001", + "denom": "btcb" + }, + "cdp_id": "1887", + "depositor": "kava15w26ypf03ew40s2rlpvz6w6zewjllux2nd9zh6" + }, + { + "amount": { + "amount": "109999996", + "denom": "btcb" + }, + "cdp_id": "1892", + "depositor": "kava1z6c9537t52clapvjzhl0r06urn9y5ptl3rdn5y" + }, + { + "amount": { + "amount": "126523785", + "denom": "btcb" + }, + "cdp_id": "1894", + "depositor": "kava1r6863cfuphfqn9e8csrh5nwt478hqys0m55jev" + }, + { + "amount": { + "amount": "5369633", + "denom": "btcb" + }, + "cdp_id": "1900", + "depositor": "kava1k8ermdwe2456hxypxdtdjhtakucwph8zjsqvaj" + }, + { + "amount": { + "amount": "499998", + "denom": "btcb" + }, + "cdp_id": "1905", + "depositor": "kava1xcku3nqxm5jt7fhgrk9pvpdqqfjkxlwx2m8aka" + }, + { + "amount": { + "amount": "1985120", + "denom": "btcb" + }, + "cdp_id": "1906", + "depositor": "kava10fu8zc5qtw2wa50z244cnlxxa3pjs8el0hc8p0" + }, + { + "amount": { + "amount": "226095", + "denom": "btcb" + }, + "cdp_id": "1908", + "depositor": "kava1jcr60d69sjymnkvdfn9vc4flxukn4gy9cd5rq9" + }, + { + "amount": { + "amount": "1299980000", + "denom": "busd" + }, + "cdp_id": "1369", + "depositor": "kava1yde8s4pa2gqqe4mz4l4aky3nxjje0r887uaauw" + }, + { + "amount": { + "amount": "1999980000", + "denom": "busd" + }, + "cdp_id": "1373", + "depositor": "kava1vlpsrmdyuywvaqrv7rx6xga224sqfwz3fyfhwq" + }, + { + "amount": { + "amount": "15989637519000", + "denom": "busd" + }, + "cdp_id": "1379", + "depositor": "kava1rea6zxqq78klh7uhf78juqp9nmtl53j7hsnquk" + }, + { + "amount": { + "amount": "200220099134", + "denom": "busd" + }, + "cdp_id": "1386", + "depositor": "kava1zuslhtgj5r8n95k833w5lttnjzuxcpjy7ql3c5" + }, + { + "amount": { + "amount": "18000000000", + "denom": "busd" + }, + "cdp_id": "1387", + "depositor": "kava13d3nklvf22whykz5a8vt8qlj66029gpwqcmj69" + }, + { + "amount": { + "amount": "132148250000", + "denom": "busd" + }, + "cdp_id": "1398", + "depositor": "kava1a7vqpgveaa97vvgh8rx2apycrjjjq4dw33hp6p" + }, + { + "amount": { + "amount": "12100000000", + "denom": "busd" + }, + "cdp_id": "1428", + "depositor": "kava1mz2vfw29fzkg4yj9wfh99nkgx46unhrxtyxqhc" + }, + { + "amount": { + "amount": "750057040000", + "denom": "busd" + }, + "cdp_id": "1430", + "depositor": "kava10lhnlwlek6yg5n734jn8qukur2kjjhcw09xagl" + }, + { + "amount": { + "amount": "14393428255", + "denom": "busd" + }, + "cdp_id": "1448", + "depositor": "kava1hlp63v8s9dmsfjumcw7sesa7gqjcj2vff7tvkq" + }, + { + "amount": { + "amount": "3507505656909", + "denom": "busd" + }, + "cdp_id": "1455", + "depositor": "kava17p6klf9l6m326ewrax8qyje78ztr6pc8auqjhj" + }, + { + "amount": { + "amount": "900472940000", + "denom": "busd" + }, + "cdp_id": "1456", + "depositor": "kava1zdtnnt6e6n949h39eskp3m3jnmzsrrda9wfl7a" + }, + { + "amount": { + "amount": "5000000000", + "denom": "busd" + }, + "cdp_id": "1458", + "depositor": "kava1fg7fcs0vupc5lyy67hatkq2nak995w3m6cvhzm" + }, + { + "amount": { + "amount": "5500000000", + "denom": "busd" + }, + "cdp_id": "1459", + "depositor": "kava1q9dmpl7y839hyvhg3w57spwfvlxls9vf9xe27h" + }, + { + "amount": { + "amount": "100416367936925", + "denom": "busd" + }, + "cdp_id": "1467", + "depositor": "kava1ahpp070dzd2fctueeufddql8eh9sx2sy54axxa" + }, + { + "amount": { + "amount": "4248159036400", + "denom": "busd" + }, + "cdp_id": "1468", + "depositor": "kava1mazzh08dgdqrn8y6khq7snr9jgun3vtlzdhq7c" + }, + { + "amount": { + "amount": "49715530000", + "denom": "busd" + }, + "cdp_id": "1471", + "depositor": "kava1c5lzj543l3xlz8s4s03phkkm4p0g6qg570vjys" + }, + { + "amount": { + "amount": "4246250860498", + "denom": "busd" + }, + "cdp_id": "1472", + "depositor": "kava1hfmlqt5qxatfzh3jnyx55ztl050ev7u6l9qefq" + }, + { + "amount": { + "amount": "514363386789", + "denom": "busd" + }, + "cdp_id": "1474", + "depositor": "kava1n8hvr4pnjfr5llkqtgpp8vt82j5jzn080t0v7d" + }, + { + "amount": { + "amount": "85925015836", + "denom": "busd" + }, + "cdp_id": "1475", + "depositor": "kava1hy7prkth4zyghgm9vj5awqc7h4gn94gw9tq3rm" + }, + { + "amount": { + "amount": "18694916116722", + "denom": "busd" + }, + "cdp_id": "1483", + "depositor": "kava1q3a9nggfp94wv6yntjt3xq9wc6gfnnkrwp2my8" + }, + { + "amount": { + "amount": "296648657419999", + "denom": "busd" + }, + "cdp_id": "1484", + "depositor": "kava1p79w5f6mallu3pqnqk6qh03xlxcmlp8hpew746" + }, + { + "amount": { + "amount": "49999999860000", + "denom": "busd" + }, + "cdp_id": "1485", + "depositor": "kava1uqm720kpl45qhvkttz5ul46qzgch7ltg0wc32j" + }, + { + "amount": { + "amount": "1181113429092", + "denom": "busd" + }, + "cdp_id": "1495", + "depositor": "kava1y56rm72h5nm6psg2k7mxx2gjtldyme2wyt2nds" + }, + { + "amount": { + "amount": "502819379035", + "denom": "busd" + }, + "cdp_id": "1499", + "depositor": "kava1mwxyxveamzwkxtnwkvcftlp4ulgexx4msuyvgr" + }, + { + "amount": { + "amount": "3259818924929", + "denom": "busd" + }, + "cdp_id": "1501", + "depositor": "kava1yw6l03x2ezr7mkpalntlj6kxxq6q049l078k69" + }, + { + "amount": { + "amount": "5922687702623", + "denom": "busd" + }, + "cdp_id": "1505", + "depositor": "kava1gr8e5w5n804gn3ypvvgdqx6535d6ukmmxcqps7" + }, + { + "amount": { + "amount": "85279066892", + "denom": "busd" + }, + "cdp_id": "1508", + "depositor": "kava1drk0qa554p4r9t4vw20sqn84m9xz7dp2gr0kfy" + }, + { + "amount": { + "amount": "484220882900", + "denom": "busd" + }, + "cdp_id": "1511", + "depositor": "kava182mzj3c7hg96fsaratn0wt2khgtgxgvlwhg77e" + }, + { + "amount": { + "amount": "145175922300", + "denom": "busd" + }, + "cdp_id": "1512", + "depositor": "kava1z0u0efzn8llallan08kenpuj262etz9392phf4" + }, + { + "amount": { + "amount": "25215725923000", + "denom": "busd" + }, + "cdp_id": "1514", + "depositor": "kava1lrrzm6celm0hp9nkm27etlyq0tp74szn2wdfg8" + }, + { + "amount": { + "amount": "1088223380000", + "denom": "busd" + }, + "cdp_id": "1517", + "depositor": "kava1rdz99mwratcl90td2t4pwvce6k3v4elyyymvx5" + }, + { + "amount": { + "amount": "19999999660000", + "denom": "busd" + }, + "cdp_id": "1519", + "depositor": "kava1nt2vxll5s7zcs7g77t8a5fl5039xnjr73z40u4" + }, + { + "amount": { + "amount": "32100000000", + "denom": "busd" + }, + "cdp_id": "1521", + "depositor": "kava1en7rx4gygys7ah237vt2tq8wwph40mx9ulwu0s" + }, + { + "amount": { + "amount": "260226427000", + "denom": "busd" + }, + "cdp_id": "1522", + "depositor": "kava1qmzley89aj4kr9l6qww75nca9zxfw8wufssuuf" + }, + { + "amount": { + "amount": "9999980000", + "denom": "busd" + }, + "cdp_id": "1523", + "depositor": "kava16hgzsqyuyf3zd3atewlz7h03pgs836x5qghxz4" + }, + { + "amount": { + "amount": "120657371620", + "denom": "busd" + }, + "cdp_id": "1543", + "depositor": "kava1dv0zgqn33sjyyx7jhxt3s9c2ug239t8fnph42q" + }, + { + "amount": { + "amount": "2071307385674", + "denom": "busd" + }, + "cdp_id": "1545", + "depositor": "kava176nfnxq2325z72jmxragelpx2jx3fme4g796pd" + }, + { + "amount": { + "amount": "6854775240", + "denom": "busd" + }, + "cdp_id": "1549", + "depositor": "kava1e7eaayk208yn8grtr7aw7xg376h4qpums7fgg8" + }, + { + "amount": { + "amount": "3465778250682", + "denom": "busd" + }, + "cdp_id": "1565", + "depositor": "kava1wjjg0mvsfgnskjj7qq28uaxqwq5h38q6nh5ah8" + }, + { + "amount": { + "amount": "7012770418578", + "denom": "busd" + }, + "cdp_id": "1574", + "depositor": "kava1f98urpz5jj0tfhm0dy6dguk8qp4fq8yr7g0fyq" + }, + { + "amount": { + "amount": "33895546575", + "denom": "busd" + }, + "cdp_id": "1577", + "depositor": "kava1t2u6mhqng5tkwkvjkj8fcp7szq2lkaffydwh2j" + }, + { + "amount": { + "amount": "73800160000", + "denom": "busd" + }, + "cdp_id": "1603", + "depositor": "kava1xwkrx4ytz6vsa5d3pc0pcsyr6twuwfdwap2vvy" + }, + { + "amount": { + "amount": "5846565792", + "denom": "busd" + }, + "cdp_id": "1615", + "depositor": "kava1nxg24gzzh9k8pl06frvp7989g3kk4ualgqkylx" + }, + { + "amount": { + "amount": "9994160000", + "denom": "busd" + }, + "cdp_id": "1630", + "depositor": "kava1a7vmnk0qfwuxq0jsek3hr798xutu24ga78s3ys" + }, + { + "amount": { + "amount": "291977292852", + "denom": "busd" + }, + "cdp_id": "1649", + "depositor": "kava15ys7x9ra820jyrwztqaps9g0dawcacvcxlap5n" + }, + { + "amount": { + "amount": "15999988680000", + "denom": "busd" + }, + "cdp_id": "1659", + "depositor": "kava1snaq99cvtjzcu9uagtw5j7guu62gpr75q0cvh5" + }, + { + "amount": { + "amount": "150797182273", + "denom": "busd" + }, + "cdp_id": "1664", + "depositor": "kava1qtp927u54rxnn8d7yfkr9dsf9xguzzy40vyyvw" + }, + { + "amount": { + "amount": "296230360000", + "denom": "busd" + }, + "cdp_id": "1665", + "depositor": "kava1fymnm880d4m03276vwwlm4xwtsswyqq07jg53s" + }, + { + "amount": { + "amount": "37025109900", + "denom": "busd" + }, + "cdp_id": "1667", + "depositor": "kava12ghgptqj954d7gr4uh0z5qesxaz3nffhkcam6r" + }, + { + "amount": { + "amount": "30270695603", + "denom": "busd" + }, + "cdp_id": "1688", + "depositor": "kava1m2unjdkmyvn8720y3guynt6q2ve59furp5cqu5" + }, + { + "amount": { + "amount": "44415960000", + "denom": "busd" + }, + "cdp_id": "1693", + "depositor": "kava1tzd292t6ykl5s4aj0qv2sp206py94z8md33aps" + }, + { + "amount": { + "amount": "2257795140000", + "denom": "busd" + }, + "cdp_id": "1694", + "depositor": "kava1kfrjwuur93wthdwc6kpf36lwftdzz22wxe5gae" + }, + { + "amount": { + "amount": "1345394580000", + "denom": "busd" + }, + "cdp_id": "1695", + "depositor": "kava149vcm760asu4uty5qlxsmkz2hh8duw2t7us7hw" + }, + { + "amount": { + "amount": "284865516543", + "denom": "busd" + }, + "cdp_id": "1699", + "depositor": "kava1famggza0sju5964gls45pmz2662fluwst53xq3" + }, + { + "amount": { + "amount": "9997080000", + "denom": "busd" + }, + "cdp_id": "1700", + "depositor": "kava1mu69p2n7ejceg504q370q2v4aulhjfudeg00tm" + }, + { + "amount": { + "amount": "988619367459", + "denom": "busd" + }, + "cdp_id": "1701", + "depositor": "kava1r0909tza7argym6587z0mnmsn6c532ew5qd06w" + }, + { + "amount": { + "amount": "11375319476621", + "denom": "busd" + }, + "cdp_id": "1706", + "depositor": "kava1as5f599ltjc9uy5dpne9pkhzuylcdhsj7sa2du" + }, + { + "amount": { + "amount": "3016813596035", + "denom": "busd" + }, + "cdp_id": "1708", + "depositor": "kava1jkxnprst3cty3jm0evz4cr077972v05y39uf9j" + }, + { + "amount": { + "amount": "42536838483", + "denom": "busd" + }, + "cdp_id": "1712", + "depositor": "kava1p42hz5v9330x7hrx07xgl5g7tw55vgkm2mdk9p" + }, + { + "amount": { + "amount": "155975327230", + "denom": "busd" + }, + "cdp_id": "1734", + "depositor": "kava127lary0erprnrv9vn3wykyt9pjm5a5tdwdnm3h" + }, + { + "amount": { + "amount": "4372659059600", + "denom": "busd" + }, + "cdp_id": "1739", + "depositor": "kava18d0er3p3esg4t0xq8nlsd568p2xh5l2rw864k0" + }, + { + "amount": { + "amount": "8496884226821", + "denom": "busd" + }, + "cdp_id": "1747", + "depositor": "kava1ctjlscze3lkppywq7mxsrytqp2ushf7vlsmjwg" + }, + { + "amount": { + "amount": "6500000000000", + "denom": "busd" + }, + "cdp_id": "1748", + "depositor": "kava1zx2gfs37vszrgrxke22mtlfj6hpl72y03ur7xr" + }, + { + "amount": { + "amount": "329699856760000", + "denom": "busd" + }, + "cdp_id": "1752", + "depositor": "kava15wyjwhj6zh79m7adm69pwl3nsq9z8gs9ezs4k7" + }, + { + "amount": { + "amount": "10877081887214", + "denom": "busd" + }, + "cdp_id": "1758", + "depositor": "kava1eu0s5hs52f4z8ld0hw3kuuwn07cgzauyda55n9" + }, + { + "amount": { + "amount": "17950000716216", + "denom": "busd" + }, + "cdp_id": "1768", + "depositor": "kava1ehtxa3cy5s5ulksfswx5c7umftlm0p2yrnc6vd" + }, + { + "amount": { + "amount": "1043400000", + "denom": "busd" + }, + "cdp_id": "1785", + "depositor": "kava19ljxvpg05r9nd03965dvh9pp22s6t7sc8zs04y" + }, + { + "amount": { + "amount": "12500000000", + "denom": "busd" + }, + "cdp_id": "1788", + "depositor": "kava1qldlnzhnjv9zeagx6a9yrqxpqrcujh8ln998mn" + }, + { + "amount": { + "amount": "16456802943", + "denom": "busd" + }, + "cdp_id": "1794", + "depositor": "kava1xu4ft9ul3jh9khrjt69rhmt6pfd3jtea0wstv8" + }, + { + "amount": { + "amount": "30000000000", + "denom": "busd" + }, + "cdp_id": "1811", + "depositor": "kava1zszzt0tlu9ry66yk7krtl8z4xn85c0ql7j64j3" + }, + { + "amount": { + "amount": "289119099333", + "denom": "busd" + }, + "cdp_id": "1812", + "depositor": "kava10fu8zc5qtw2wa50z244cnlxxa3pjs8el0hc8p0" + }, + { + "amount": { + "amount": "1149909240000", + "denom": "busd" + }, + "cdp_id": "1814", + "depositor": "kava1zrthvpd9rjmyapya6xxf2ywrs4h3ugfmfw4rzu" + }, + { + "amount": { + "amount": "4800000000", + "denom": "busd" + }, + "cdp_id": "1819", + "depositor": "kava1t7v48gu6jh26av0e089sxq4n4jxwckp8v7hp6p" + }, + { + "amount": { + "amount": "5999999980000", + "denom": "busd" + }, + "cdp_id": "1821", + "depositor": "kava1nr3a995c3ywl8d4cplczsavvtfd5qhetffypd2" + }, + { + "amount": { + "amount": "1099999980000", + "denom": "busd" + }, + "cdp_id": "1822", + "depositor": "kava15jtcnhucatrg8z70s5huxpyhnwf2klupv6xqyq" + }, + { + "amount": { + "amount": "202729450101", + "denom": "busd" + }, + "cdp_id": "1831", + "depositor": "kava1caukx55c2qcgcy94ny4y97jag8nst6nwcat06j" + }, + { + "amount": { + "amount": "1000000000000", + "denom": "busd" + }, + "cdp_id": "1836", + "depositor": "kava1c2hulueujetjcpgwlnu07t47yg77rq3fxrqk0f" + }, + { + "amount": { + "amount": "1099864867155", + "denom": "busd" + }, + "cdp_id": "1837", + "depositor": "kava15adrjuvyk62x0klyukaums95frw5usm4v6daj9" + }, + { + "amount": { + "amount": "29990000000000", + "denom": "busd" + }, + "cdp_id": "1841", + "depositor": "kava1tstf3u4cw7u4xyu7wxdrnmrpvvmfamq3twcj7f" + }, + { + "amount": { + "amount": "259852315955", + "denom": "busd" + }, + "cdp_id": "1844", + "depositor": "kava1wkn6z4xjrl2esflpdvxemn0m8hkv34ygh6xeaf" + }, + { + "amount": { + "amount": "500094180000", + "denom": "busd" + }, + "cdp_id": "1845", + "depositor": "kava1tnf0zwaqx76lkpaj0un36kvwhver8dmynvr6zs" + }, + { + "amount": { + "amount": "25459258855138", + "denom": "busd" + }, + "cdp_id": "1846", + "depositor": "kava19mtegk4rd6fjfxjsmknn8862gcmfd32myj7sva" + }, + { + "amount": { + "amount": "199794180000", + "denom": "busd" + }, + "cdp_id": "1855", + "depositor": "kava1a97dqz7ptwv2pxrgcrp8a2e6vap6utj83av20k" + }, + { + "amount": { + "amount": "228306404000", + "denom": "busd" + }, + "cdp_id": "1856", + "depositor": "kava10rmx7epkes54py97gjpn5qwr3xgjaln2f3yadl" + }, + { + "amount": { + "amount": "118637080000", + "denom": "busd" + }, + "cdp_id": "1859", + "depositor": "kava18zpjg8wc9mmgkvsl5sg3esk7yrns6gsy4rs3ra" + }, + { + "amount": { + "amount": "1400000000", + "denom": "busd" + }, + "cdp_id": "1868", + "depositor": "kava1dz5zhsa0uxw62y06mwmaazgkhgq49e7sun6nf3" + }, + { + "amount": { + "amount": "1400000000", + "denom": "busd" + }, + "cdp_id": "1869", + "depositor": "kava1ha8cwpay5l293clga0sy0ersm8tqmv0gfgaejc" + }, + { + "amount": { + "amount": "65000000000", + "denom": "busd" + }, + "cdp_id": "1870", + "depositor": "kava1chk4a3v96nhc5msc5f84f66ulujz7xdz9fh367" + }, + { + "amount": { + "amount": "12361661289391", + "denom": "busd" + }, + "cdp_id": "1873", + "depositor": "kava1tc5mkjya8upt82f3puaqdgahec520pw8zc2vd2" + }, + { + "amount": { + "amount": "12862026100", + "denom": "busd" + }, + "cdp_id": "1877", + "depositor": "kava1dfymyx0q5jzq363whtcerdlug3jeyujwayn4vn" + }, + { + "amount": { + "amount": "7358475000", + "denom": "busd" + }, + "cdp_id": "1888", + "depositor": "kava1tzzdns8zkl0qptywnpr27eh0evj9zu45pc8f0g" + }, + { + "amount": { + "amount": "10483560000", + "denom": "busd" + }, + "cdp_id": "1889", + "depositor": "kava1pmaltcu0x97x8j5klc8xluaapkzcvztcvvvcnw" + }, + { + "amount": { + "amount": "799994160000", + "denom": "busd" + }, + "cdp_id": "1890", + "depositor": "kava1r6863cfuphfqn9e8csrh5nwt478hqys0m55jev" + }, + { + "amount": { + "amount": "100602380000", + "denom": "busd" + }, + "cdp_id": "1893", + "depositor": "kava10l6gr3u8xqfd8jps724n4hkhd92fh9rugyx2n7" + }, + { + "amount": { + "amount": "9999980000", + "denom": "busd" + }, + "cdp_id": "1898", + "depositor": "kava1r52nyu8agn30xrm5yfu2npsthcqle9yck3fhtf" + }, + { + "amount": { + "amount": "755499980000", + "denom": "busd" + }, + "cdp_id": "1902", + "depositor": "kava1vg6q5k7q6s89lk852dgle8c5fr3rmrrr3jsvhy" + }, + { + "amount": { + "amount": "1096537081867", + "denom": "busd" + }, + "cdp_id": "1903", + "depositor": "kava1ev5lnr4h8fhljgdtfe9gwlff4vg9ea6j8uxu3a" + }, + { + "amount": { + "amount": "5960458109170", + "denom": "busd" + }, + "cdp_id": "1904", + "depositor": "kava15w26ypf03ew40s2rlpvz6w6zewjllux2nd9zh6" + }, + { + "amount": { + "amount": "60000046735124", + "denom": "busd" + }, + "cdp_id": "1907", + "depositor": "kava10wyahu4d23fgtzjdxc998gn7z48lc2nte79z37" + }, + { + "amount": { + "amount": "2620118448775", + "denom": "busd" + }, + "cdp_id": "1909", + "depositor": "kava1dn23hf3h0ysfh8j6t7f6vp95unvfet7qlgrkv4" + }, + { + "amount": { + "amount": "60023680000", + "denom": "busd" + }, + "cdp_id": "1912", + "depositor": "kava19skxg5ce7j3l2nthpc0xcjuxj2sykjyht0dfs7" + }, + { + "amount": { + "amount": "813548595054", + "denom": "busd" + }, + "cdp_id": "1913", + "depositor": "kava1dpcgtp7hjvspg7nxpj7c7j25lnyyrau0g72jkd" + }, + { + "amount": { + "amount": "25000000000", + "denom": "busd" + }, + "cdp_id": "1914", + "depositor": "kava1xcku3nqxm5jt7fhgrk9pvpdqqfjkxlwx2m8aka" + }, + { + "amount": { + "amount": "6700000000", + "denom": "busd" + }, + "cdp_id": "1915", + "depositor": "kava1zu4g7frl94szncff5marn63lurrk8rggterfvc" + }, + { + "amount": { + "amount": "39816021000", + "denom": "busd" + }, + "cdp_id": "1919", + "depositor": "kava13za9r4nk42aqkt8fw79wzf9r56gjatpc58ahvy" + }, + { + "amount": { + "amount": "3006990000", + "denom": "busd" + }, + "cdp_id": "1534", + "depositor": "kava1ed0esw7jp8w580r052rhna5q8elw26y9a2td60" + }, + { + "amount": { + "amount": "18900000000", + "denom": "busd" + }, + "cdp_id": "1539", + "depositor": "kava1kldesu66y2telgvupaknyzx8ague6kk5kz052e" + }, + { + "amount": { + "amount": "1199960000", + "denom": "busd" + }, + "cdp_id": "1592", + "depositor": "kava1ns8hmay6uh3p4j8ydr0hrvh0nxq9yu260xqchw" + }, + { + "amount": { + "amount": "78007141034", + "denom": "busd" + }, + "cdp_id": "1839", + "depositor": "kava1w05lzr3tj72n33vam3v0qddq05hf605a6k92u5" + }, + { + "amount": { + "amount": "1314442237", + "denom": "busd" + }, + "cdp_id": "1862", + "depositor": "kava1gl9904w9u3znw9hy7eh7durrqnwdq44rastfyt" + }, + { + "amount": { + "amount": "25000000000", + "denom": "xrpb" + }, + "cdp_id": "1375", + "depositor": "kava1vlpsrmdyuywvaqrv7rx6xga224sqfwz3fyfhwq" + }, + { + "amount": { + "amount": "1004962800000", + "denom": "xrpb" + }, + "cdp_id": "1381", + "depositor": "kava1zuslhtgj5r8n95k833w5lttnjzuxcpjy7ql3c5" + }, + { + "amount": { + "amount": "8520808428", + "denom": "xrpb" + }, + "cdp_id": "1382", + "depositor": "kava1sz6sm2arpa0cgufngdl04yxn4t2kyhepaf4klk" + }, + { + "amount": { + "amount": "10312687900", + "denom": "xrpb" + }, + "cdp_id": "1402", + "depositor": "kava1lynr3f7zqhpcwacvatewcwj0ar5q9sgx7tesj4" + }, + { + "amount": { + "amount": "199334393490", + "denom": "xrpb" + }, + "cdp_id": "1435", + "depositor": "kava1sxhs7nrnmz5ypxjjx809wk92wy3uwz0x456r8w" + }, + { + "amount": { + "amount": "24527390000", + "denom": "xrpb" + }, + "cdp_id": "1436", + "depositor": "kava1hlp63v8s9dmsfjumcw7sesa7gqjcj2vff7tvkq" + }, + { + "amount": { + "amount": "299977800000", + "denom": "xrpb" + }, + "cdp_id": "1437", + "depositor": "kava1n5eml55pqa3nm74rw589l3uqzmafytcz4e37zv" + }, + { + "amount": { + "amount": "8131036400", + "denom": "xrpb" + }, + "cdp_id": "1469", + "depositor": "kava15neu5ermme78khn448pwqqdthy4zl2pxaec780" + }, + { + "amount": { + "amount": "9480972600", + "denom": "xrpb" + }, + "cdp_id": "1470", + "depositor": "kava1cq0pd4w270sl65fvp4w067exxhhnvagfxcvn36" + }, + { + "amount": { + "amount": "500017800000", + "denom": "xrpb" + }, + "cdp_id": "1516", + "depositor": "kava1nzq60hrphyr8anvkw6fv93mhafew7ez4tq9ahv" + }, + { + "amount": { + "amount": "8065491200", + "denom": "xrpb" + }, + "cdp_id": "1531", + "depositor": "kava10l6gr3u8xqfd8jps724n4hkhd92fh9rugyx2n7" + }, + { + "amount": { + "amount": "1015099900000", + "denom": "xrpb" + }, + "cdp_id": "1579", + "depositor": "kava18utzytkj0unzevcm4jzxncu95prc8x5wqcnt9n" + }, + { + "amount": { + "amount": "149999900000", + "denom": "xrpb" + }, + "cdp_id": "1740", + "depositor": "kava1h346y43zgpuexpdanq5850e4kktq0dcy4tfxd4" + }, + { + "amount": { + "amount": "1000914340000", + "denom": "xrpb" + }, + "cdp_id": "1756", + "depositor": "kava1eu0s5hs52f4z8ld0hw3kuuwn07cgzauyda55n9" + }, + { + "amount": { + "amount": "606339600000", + "denom": "xrpb" + }, + "cdp_id": "1834", + "depositor": "kava15aemgl7ymdqc80wczqynms2wz0efvsf4hs0dhj" + }, + { + "amount": { + "amount": "59231000000", + "denom": "xrpb" + }, + "cdp_id": "1884", + "depositor": "kava1t2u6mhqng5tkwkvjkj8fcp7szq2lkaffydwh2j" + }, + { + "amount": { + "amount": "2802099800000", + "denom": "xrpb" + }, + "cdp_id": "1885", + "depositor": "kava1alt4u48umfqgx6uwuhvu5qts67t78p86ejlv5y" + }, + { + "amount": { + "amount": "359290500000", + "denom": "xrpb" + }, + "cdp_id": "1899", + "depositor": "kava1rea6zxqq78klh7uhf78juqp9nmtl53j7hsnquk" + } + ], + "gov_denom": "ukava", + "params": { + "circuit_breaker": false, + "collateral_params": [ + { + "auction_size": "50000000000", + "conversion_factor": "8", + "debt_limit": { + "amount": "30000000000000", + "denom": "usdx" + }, + "denom": "bnb", + "liquidation_market_id": "bnb:usd:30", + "liquidation_penalty": "0.075000000000000000", + "liquidation_ratio": "1.500000000000000000", + "prefix": 1, + "spot_market_id": "bnb:usd", + "stability_fee": "1.000000000158153904", + "type": "bnb-a" + }, + { + "auction_size": "100000000", + "conversion_factor": "8", + "debt_limit": { + "amount": "15000000000000", + "denom": "usdx" + }, + "denom": "btcb", + "liquidation_market_id": "btc:usd:30", + "liquidation_penalty": "0.075000000000000000", + "liquidation_ratio": "1.500000000000000000", + "prefix": 2, + "spot_market_id": "btc:usd", + "stability_fee": "1.000000001547125958", + "type": "btcb-a" + }, + { + "auction_size": "1000000000000", + "conversion_factor": "8", + "debt_limit": { + "amount": "50000000000000", + "denom": "usdx" + }, + "denom": "busd", + "liquidation_market_id": "busd:usd:30", + "liquidation_penalty": "0.075000000000000000", + "liquidation_ratio": "1.010000000000000000", + "prefix": 3, + "spot_market_id": "busd:usd", + "stability_fee": "1.000000000000000000", + "type": "busd-a" + }, + { + "auction_size": "1000000000000", + "conversion_factor": "8", + "debt_limit": { + "amount": "10000000000000", + "denom": "usdx" + }, + "denom": "busd", + "liquidation_market_id": "busd:usd:30", + "liquidation_penalty": "0.075000000000000000", + "liquidation_ratio": "1.100000000000000000", + "prefix": 4, + "spot_market_id": "busd:usd", + "stability_fee": "1.000000012857214317", + "type": "busd-b" + }, + { + "auction_size": "4000000000000", + "conversion_factor": "8", + "debt_limit": { + "amount": "7500000000000", + "denom": "usdx" + }, + "denom": "xrpb", + "liquidation_market_id": "xrp:usd:30", + "liquidation_penalty": "0.075000000000000000", + "liquidation_ratio": "1.500000000000000000", + "prefix": 5, + "spot_market_id": "xrp:usd", + "stability_fee": "1.000000001547125958", + "type": "xrpb-a" + } + ], + "debt_auction_lot": "10000000000", + "debt_auction_threshold": "50000000000", + "debt_param": { + "conversion_factor": "6", + "debt_floor": "10000000", + "denom": "usdx", + "reference_asset": "usd", + "savings_rate": "0.000000000000000000" + }, + "global_debt_limit": { + "amount": "112500000000000", + "denom": "usdx" + }, + "savings_distribution_frequency": "31540000000000000", + "surplus_auction_lot": "10000000000", + "surplus_auction_threshold": "200000000000" + }, + "previous_distribution_time": "2020-10-05T23:38:38.212336021Z", + "savings_rate_distributed": "0", + "starting_cdp_id": "1920" +} diff --git a/x/auction/types/auctions.go b/x/auction/types/auctions.go index 95ec1095..860a4a98 100644 --- a/x/auction/types/auctions.go +++ b/x/auction/types/auctions.go @@ -272,10 +272,11 @@ func (a CollateralAuction) String() string { End Time: %s Max End Time: %s Max Bid %s - LotReturns %s`, + LotReturns %s + Corresponding Debt %s`, a.GetID(), a.Initiator, a.Lot, a.Bidder, a.Bid, a.GetEndTime().String(), - a.MaxEndTime.String(), a.MaxBid, a.LotReturns, + a.MaxEndTime.String(), a.MaxBid, a.LotReturns, a.CorrespondingDebt, ) } diff --git a/x/cdp/abci.go b/x/cdp/abci.go index 3e2127c0..9f5c5290 100644 --- a/x/cdp/abci.go +++ b/x/cdp/abci.go @@ -14,12 +14,6 @@ import ( func BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock, k Keeper) { params := k.GetParams(ctx) - previousDistTime, found := k.GetPreviousSavingsDistribution(ctx) - if !found { - previousDistTime = ctx.BlockTime() - k.SetPreviousSavingsDistribution(ctx, previousDistTime) - } - for _, cp := range params.CollateralParams { ok := k.UpdatePricefeedStatus(ctx, cp.SpotMarketID) if !ok { @@ -31,7 +25,12 @@ func BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock, k Keeper) { continue } - err := k.UpdateFeesForAllCdps(ctx, cp.Type) + err := k.AccumulateInterest(ctx, cp.Type) + if err != nil { + panic(err) + } + + err = k.SynchronizeInterestForRiskyCDPs(ctx, cp.CheckCollateralizationIndexCount, sdk.MaxSortableDec, cp.Type) if err != nil { panic(err) } @@ -46,16 +45,4 @@ func BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock, k Keeper) { if err != nil { panic(err) } - - distTimeElapsed := sdk.NewInt(ctx.BlockTime().Unix() - previousDistTime.Unix()) - if !distTimeElapsed.GTE(sdk.NewInt(int64(params.SavingsDistributionFrequency.Seconds()))) { - return - } - - err = k.DistributeSavingsRate(ctx, params.DebtParam.Denom) - if err != nil { - panic(err) - } - - k.SetPreviousSavingsDistribution(ctx, ctx.BlockTime()) } diff --git a/x/cdp/abci_test.go b/x/cdp/abci_test.go index 9ddeed86..13d68363 100644 --- a/x/cdp/abci_test.go +++ b/x/cdp/abci_test.go @@ -165,7 +165,7 @@ func (suite *ModuleTestSuite) TestSeizeSingleCdpWithFees() { } cdpMacc = sk.GetModuleAccount(suite.ctx, cdp.ModuleName) - suite.Equal(i(1000000900), (cdpMacc.GetCoins().AmountOf("debt"))) + suite.Equal(i(1000000891), (cdpMacc.GetCoins().AmountOf("debt"))) cdp, _ := suite.keeper.GetCDP(suite.ctx, "xrp-a", 1) err = suite.keeper.SeizeCollateral(suite.ctx, cdp) diff --git a/x/cdp/alias.go b/x/cdp/alias.go index 6c3bbce3..75b463a3 100644 --- a/x/cdp/alias.go +++ b/x/cdp/alias.go @@ -8,7 +8,6 @@ import ( ) const ( - BaseDigitFactor = keeper.BaseDigitFactor AttributeKeyCdpID = types.AttributeKeyCdpID AttributeKeyDeposit = types.AttributeKeyDeposit AttributeKeyError = types.AttributeKeyError @@ -38,12 +37,12 @@ const ( RestOwner = types.RestOwner RestRatio = types.RestRatio RouterKey = types.RouterKey - SavingsRateMacc = types.SavingsRateMacc StoreKey = types.StoreKey ) var ( // function aliases + CalculateInterestFactor = keeper.CalculateInterestFactor FilterCDPs = keeper.FilterCDPs FindIntersection = keeper.FindIntersection NewKeeper = keeper.NewKeeper @@ -65,12 +64,16 @@ var ( NewCollateralParam = types.NewCollateralParam NewDebtParam = types.NewDebtParam NewDeposit = types.NewDeposit + NewGenesisAccumulationTime = types.NewGenesisAccumulationTime NewGenesisState = types.NewGenesisState + NewGenesisTotalPrincipal = types.NewGenesisTotalPrincipal NewMsgCreateCDP = types.NewMsgCreateCDP NewMsgDeposit = types.NewMsgDeposit NewMsgDrawDebt = types.NewMsgDrawDebt + NewMsgLiquidate = types.NewMsgLiquidate NewMsgRepayDebt = types.NewMsgRepayDebt NewMsgWithdraw = types.NewMsgWithdraw + NewMultiCDPHooks = types.NewMultiCDPHooks NewParams = types.NewParams NewQueryCdpDeposits = types.NewQueryCdpDeposits NewQueryCdpParams = types.NewQueryCdpParams @@ -91,63 +94,62 @@ var ( ValidSortableDec = types.ValidSortableDec // variable aliases - CdpIDKey = types.CdpIDKey - CdpIDKeyPrefix = types.CdpIDKeyPrefix - CdpKeyPrefix = types.CdpKeyPrefix - CollateralRatioIndexPrefix = types.CollateralRatioIndexPrefix - DebtDenomKey = types.DebtDenomKey - DefaultCdpStartingID = types.DefaultCdpStartingID - DefaultCircuitBreaker = types.DefaultCircuitBreaker - DefaultCollateralParams = types.DefaultCollateralParams - DefaultDebtDenom = types.DefaultDebtDenom - DefaultDebtLot = types.DefaultDebtLot - DefaultDebtParam = types.DefaultDebtParam - DefaultDebtThreshold = types.DefaultDebtThreshold - DefaultGlobalDebt = types.DefaultGlobalDebt - DefaultGovDenom = types.DefaultGovDenom - DefaultPreviousDistributionTime = types.DefaultPreviousDistributionTime - DefaultSavingsDistributionFrequency = types.DefaultSavingsDistributionFrequency - DefaultSavingsRateDistributed = types.DefaultSavingsRateDistributed - DefaultStableDenom = types.DefaultStableDenom - DefaultSurplusLot = types.DefaultSurplusLot - DefaultSurplusThreshold = types.DefaultSurplusThreshold - DepositKeyPrefix = types.DepositKeyPrefix - ErrBelowDebtFloor = types.ErrBelowDebtFloor - ErrCdpAlreadyExists = types.ErrCdpAlreadyExists - ErrCdpNotAvailable = types.ErrCdpNotAvailable - ErrCdpNotFound = types.ErrCdpNotFound - ErrCollateralNotSupported = types.ErrCollateralNotSupported - ErrDebtNotSupported = types.ErrDebtNotSupported - ErrDenomPrefixNotFound = types.ErrDenomPrefixNotFound - ErrDepositNotAvailable = types.ErrDepositNotAvailable - ErrDepositNotFound = types.ErrDepositNotFound - ErrExceedsDebtLimit = types.ErrExceedsDebtLimit - ErrInvalidCollateral = types.ErrInvalidCollateral - ErrInvalidCollateralLength = types.ErrInvalidCollateralLength - ErrInvalidCollateralRatio = types.ErrInvalidCollateralRatio - ErrInvalidDebtRequest = types.ErrInvalidDebtRequest - ErrInvalidDeposit = types.ErrInvalidDeposit - ErrInvalidPayment = types.ErrInvalidPayment - ErrInvalidWithdrawAmount = types.ErrInvalidWithdrawAmount - ErrLoadingAugmentedCDP = types.ErrLoadingAugmentedCDP - ErrPricefeedDown = types.ErrPricefeedDown - GovDenomKey = types.GovDenomKey - KeyCircuitBreaker = types.KeyCircuitBreaker - KeyCollateralParams = types.KeyCollateralParams - KeyDebtLot = types.KeyDebtLot - KeyDebtParam = types.KeyDebtParam - KeyDebtThreshold = types.KeyDebtThreshold - KeyDistributionFrequency = types.KeyDistributionFrequency - KeyGlobalDebtLimit = types.KeyGlobalDebtLimit - KeySavingsRateDistributed = types.KeySavingsRateDistributed - KeySurplusLot = types.KeySurplusLot - KeySurplusThreshold = types.KeySurplusThreshold - MaxSortableDec = types.MaxSortableDec - ModuleCdc = types.ModuleCdc - PreviousDistributionTimeKey = types.PreviousDistributionTimeKey - PricefeedStatusKeyPrefix = types.PricefeedStatusKeyPrefix - PrincipalKeyPrefix = types.PrincipalKeyPrefix - SavingsRateDistributedKey = types.SavingsRateDistributedKey + CdpIDKey = types.CdpIDKey + CdpIDKeyPrefix = types.CdpIDKeyPrefix + CdpKeyPrefix = types.CdpKeyPrefix + CollateralRatioIndexPrefix = types.CollateralRatioIndexPrefix + DebtDenomKey = types.DebtDenomKey + DefaultCdpStartingID = types.DefaultCdpStartingID + DefaultCircuitBreaker = types.DefaultCircuitBreaker + DefaultCollateralParams = types.DefaultCollateralParams + DefaultDebtDenom = types.DefaultDebtDenom + DefaultDebtLot = types.DefaultDebtLot + DefaultDebtParam = types.DefaultDebtParam + DefaultDebtThreshold = types.DefaultDebtThreshold + DefaultGlobalDebt = types.DefaultGlobalDebt + DefaultGovDenom = types.DefaultGovDenom + DefaultSavingsRateDistributed = types.DefaultSavingsRateDistributed + DefaultStableDenom = types.DefaultStableDenom + DefaultSurplusLot = types.DefaultSurplusLot + DefaultSurplusThreshold = types.DefaultSurplusThreshold + DepositKeyPrefix = types.DepositKeyPrefix + ErrAccountNotFound = types.ErrAccountNotFound + ErrBelowDebtFloor = types.ErrBelowDebtFloor + ErrCdpAlreadyExists = types.ErrCdpAlreadyExists + ErrCdpNotAvailable = types.ErrCdpNotAvailable + ErrCdpNotFound = types.ErrCdpNotFound + ErrCollateralNotSupported = types.ErrCollateralNotSupported + ErrDebtNotSupported = types.ErrDebtNotSupported + ErrDenomPrefixNotFound = types.ErrDenomPrefixNotFound + ErrDepositNotAvailable = types.ErrDepositNotAvailable + ErrDepositNotFound = types.ErrDepositNotFound + ErrExceedsDebtLimit = types.ErrExceedsDebtLimit + ErrInsufficientBalance = types.ErrInsufficientBalance + ErrInvalidCollateral = types.ErrInvalidCollateral + ErrInvalidCollateralLength = types.ErrInvalidCollateralLength + ErrInvalidCollateralRatio = types.ErrInvalidCollateralRatio + ErrInvalidDebtRequest = types.ErrInvalidDebtRequest + ErrInvalidDeposit = types.ErrInvalidDeposit + ErrInvalidPayment = types.ErrInvalidPayment + ErrInvalidWithdrawAmount = types.ErrInvalidWithdrawAmount + ErrLoadingAugmentedCDP = types.ErrLoadingAugmentedCDP + ErrNotLiquidatable = types.ErrNotLiquidatable + ErrPricefeedDown = types.ErrPricefeedDown + GovDenomKey = types.GovDenomKey + InterestFactorPrefix = types.InterestFactorPrefix + KeyCircuitBreaker = types.KeyCircuitBreaker + KeyCollateralParams = types.KeyCollateralParams + KeyDebtLot = types.KeyDebtLot + KeyDebtParam = types.KeyDebtParam + KeyDebtThreshold = types.KeyDebtThreshold + KeyGlobalDebtLimit = types.KeyGlobalDebtLimit + KeySurplusLot = types.KeySurplusLot + KeySurplusThreshold = types.KeySurplusThreshold + MaxSortableDec = types.MaxSortableDec + ModuleCdc = types.ModuleCdc + PreviousAccrualTimePrefix = types.PreviousAccrualTimePrefix + PricefeedStatusKeyPrefix = types.PricefeedStatusKeyPrefix + PrincipalKeyPrefix = types.PrincipalKeyPrefix ) type ( @@ -157,6 +159,7 @@ type ( AugmentedCDP = types.AugmentedCDP AugmentedCDPs = types.AugmentedCDPs CDP = types.CDP + CDPHooks = types.CDPHooks CDPs = types.CDPs CollateralParam = types.CollateralParam CollateralParams = types.CollateralParams @@ -164,12 +167,18 @@ type ( DebtParams = types.DebtParams Deposit = types.Deposit Deposits = types.Deposits + GenesisAccumulationTime = types.GenesisAccumulationTime + GenesisAccumulationTimes = types.GenesisAccumulationTimes GenesisState = types.GenesisState + GenesisTotalPrincipal = types.GenesisTotalPrincipal + GenesisTotalPrincipals = types.GenesisTotalPrincipals MsgCreateCDP = types.MsgCreateCDP MsgDeposit = types.MsgDeposit MsgDrawDebt = types.MsgDrawDebt + MsgLiquidate = types.MsgLiquidate MsgRepayDebt = types.MsgRepayDebt MsgWithdraw = types.MsgWithdraw + MultiCDPHooks = types.MultiCDPHooks Params = types.Params PricefeedKeeper = types.PricefeedKeeper QueryCdpDeposits = types.QueryCdpDeposits diff --git a/x/cdp/client/cli/query.go b/x/cdp/client/cli/query.go index 7ec5a41e..1034b88d 100644 --- a/x/cdp/client/cli/query.go +++ b/x/cdp/client/cli/query.go @@ -4,7 +4,6 @@ import ( "fmt" "strconv" "strings" - "time" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -41,8 +40,6 @@ func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { QueryCdpDepositsCmd(queryRoute, cdc), QueryParamsCmd(queryRoute, cdc), QueryGetAccounts(queryRoute, cdc), - QueryGetSavingsRateDistributed(queryRoute, cdc), - QueryGetSavingsRateDistTime(queryRoute, cdc), )...) return cdpQueryCmd @@ -284,56 +281,3 @@ func QueryGetAccounts(queryRoute string, cdc *codec.Codec) *cobra.Command { }, } } - -// QueryGetSavingsRateDistributed queries the total amount of savings rate distributed in USDX -func QueryGetSavingsRateDistributed(queryRoute string, cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "savings-rate-dist", - Short: "get total amount of savings rate distributed in USDX", - Long: "get total amount of savings rate distributed", - Args: cobra.NoArgs, - RunE: func(cmd *cobra.Command, args []string) error { - cliCtx := context.NewCLIContext().WithCodec(cdc) - - // Query - res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryGetSavingsRateDistributed), nil) - if err != nil { - return err - } - cliCtx = cliCtx.WithHeight(height) - - // Decode and print results - var out sdk.Int - if err := cdc.UnmarshalJSON(res, &out); err != nil { - return fmt.Errorf("failed to unmarshal sdk.Int: %w", err) - } - return cliCtx.PrintOutput(out) - }, - } -} - -// QueryGetSavingsRateDistributed queries the total amount of savings rate distributed in USDX -func QueryGetSavingsRateDistTime(queryRoute string, cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "savings-rate-dist-time", - Short: "get the previous savings rate distribution time", - Args: cobra.NoArgs, - RunE: func(cmd *cobra.Command, args []string) error { - cliCtx := context.NewCLIContext().WithCodec(cdc) - - // Query - res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryGetPreviousSavingsDistributionTime), nil) - if err != nil { - return err - } - cliCtx = cliCtx.WithHeight(height) - - // Decode and print results - var out time.Time - if err := cdc.UnmarshalJSON(res, &out); err != nil { - return fmt.Errorf("failed to unmarshal time.Time: %w", err) - } - return cliCtx.PrintOutput(out) - }, - } -} diff --git a/x/cdp/client/cli/tx.go b/x/cdp/client/cli/tx.go index 0ce5c82d..e5a5311c 100644 --- a/x/cdp/client/cli/tx.go +++ b/x/cdp/client/cli/tx.go @@ -31,6 +31,7 @@ func GetTxCmd(cdc *codec.Codec) *cobra.Command { GetCmdWithdraw(cdc), GetCmdDraw(cdc), GetCmdRepay(cdc), + GetCmdLiquidate(cdc), )...) return cdpTxCmd @@ -202,3 +203,34 @@ $ %s tx %s repay atom-a 1000usdx --from myKeyName }, } } + +// GetCmdLiquidate cli command for liquidating a cdp. +func GetCmdLiquidate(cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "liquidate [cdp-owner-address] [collateral-type]", + Short: "liquidate a cdp", + Long: strings.TrimSpace( + fmt.Sprintf(`Liquidate a cdp if it is below the required liquidation ratio + +Example: +$ %s tx %s liquidate kava1y70y90wzmnf00e63efk2lycgqwepthdmyzsfzm btcb-a --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(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc)) + + addr, err := sdk.AccAddressFromBech32(args[0]) + if err != nil { + return err + } + msg := types.NewMsgLiquidate(cliCtx.GetFromAddress(), addr, args[1]) + err = msg.ValidateBasic() + if err != nil { + return err + } + return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } +} diff --git a/x/cdp/client/rest/query.go b/x/cdp/client/rest/query.go index fe4645c4..6f3ff641 100644 --- a/x/cdp/client/rest/query.go +++ b/x/cdp/client/rest/query.go @@ -18,8 +18,6 @@ import ( func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router) { r.HandleFunc("/cdp/accounts", getAccountsHandlerFn(cliCtx)).Methods("GET") r.HandleFunc("/cdp/parameters", getParamsHandlerFn(cliCtx)).Methods("GET") - r.HandleFunc("/cdp/savingsRateDist", getSavingsRateDistributedHandler(cliCtx)).Methods("GET") - r.HandleFunc("/cdp/savingsRateDistTime", getSavingsRateDistTimeHandler(cliCtx)).Methods("GET") r.HandleFunc(fmt.Sprintf("/cdp/cdps/cdp/{%s}/{%s}", types.RestOwner, types.RestCollateralType), queryCdpHandlerFn(cliCtx)).Methods("GET") r.HandleFunc(fmt.Sprintf("/cdp/cdps"), queryCdpsHandlerFn(cliCtx)).Methods("GET") r.HandleFunc(fmt.Sprintf("/cdp/cdps/collateralType/{%s}", types.RestCollateralType), queryCdpsByCollateralTypeHandlerFn(cliCtx)).Methods("GET") // legacy @@ -199,42 +197,6 @@ func getAccountsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { } } -func getSavingsRateDistributedHandler(cliCtx context.CLIContext) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) - if !ok { - return - } - - res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/cdp/%s", types.QueryGetSavingsRateDistributed), nil) - cliCtx = cliCtx.WithHeight(height) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) - return - } - - rest.PostProcessResponse(w, cliCtx, res) - } -} - -func getSavingsRateDistTimeHandler(cliCtx context.CLIContext) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) - if !ok { - return - } - - res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/cdp/%s", types.QueryGetPreviousSavingsDistributionTime), nil) - cliCtx = cliCtx.WithHeight(height) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) - return - } - - rest.PostProcessResponse(w, cliCtx, res) - } -} - func queryCdpsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { _, page, limit, err := rest.ParseHTTPArgsWithLimit(r, 0) diff --git a/x/cdp/client/rest/rest.go b/x/cdp/client/rest/rest.go index 068c4cdb..4584b7be 100644 --- a/x/cdp/client/rest/rest.go +++ b/x/cdp/client/rest/rest.go @@ -65,3 +65,10 @@ type PostRepayReq struct { CollateralType string `json:"collateral_type" yaml:"collateral_type"` Payment sdk.Coin `json:"payment" yaml:"payment"` } + +// PostLiquidateReq defines the properties of cdp liquidation request's body. +type PostLiquidateReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + Owner sdk.AccAddress `json:"owner" yaml:"owner"` + CollateralType string `json:"collateral_type" yaml:"collateral_type"` +} diff --git a/x/cdp/client/rest/tx.go b/x/cdp/client/rest/tx.go index 154d9b39..2c66a588 100644 --- a/x/cdp/client/rest/tx.go +++ b/x/cdp/client/rest/tx.go @@ -20,6 +20,7 @@ func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router) { r.HandleFunc("/cdp/{owner}/{collateralType}/withdraw", postWithdrawHandlerFn(cliCtx)).Methods("POST") r.HandleFunc("/cdp/{owner}/{collateralType}/draw", postDrawHandlerFn(cliCtx)).Methods("POST") r.HandleFunc("/cdp/{owner}/{collateralType}/repay", postRepayHandlerFn(cliCtx)).Methods("POST") + r.HandleFunc("/cdp/{owner}/collateralType}/liquidate", postLiquidateHandlerFn(cliCtx)).Methods("POST") } func postCdpHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { @@ -187,3 +188,35 @@ func postRepayHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { utils.WriteGenerateStdTxResponse(w, cliCtx, requestBody.BaseReq, []sdk.Msg{msg}) } } + +func postLiquidateHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var requestBody PostLiquidateReq + if !rest.ReadRESTReq(w, r, cliCtx.Codec, &requestBody) { + return + } + + requestBody.BaseReq = requestBody.BaseReq.Sanitize() + if !requestBody.BaseReq.ValidateBasic(w) { + return + } + + fromAddr, err := sdk.AccAddressFromBech32(requestBody.BaseReq.From) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + msg := types.NewMsgLiquidate( + fromAddr, + requestBody.Owner, + requestBody.CollateralType, + ) + if err := msg.ValidateBasic(); err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + utils.WriteGenerateStdTxResponse(w, cliCtx, requestBody.BaseReq, []sdk.Msg{msg}) + } +} diff --git a/x/cdp/genesis.go b/x/cdp/genesis.go index 95936958..5da2089c 100644 --- a/x/cdp/genesis.go +++ b/x/cdp/genesis.go @@ -24,10 +24,6 @@ func InitGenesis(ctx sdk.Context, k Keeper, pk types.PricefeedKeeper, sk types.S if liqModuleAcc == nil { panic(fmt.Sprintf("%s module account has not been set", LiquidatorMacc)) } - savingsRateMacc := sk.GetModuleAccount(ctx, SavingsRateMacc) - if savingsRateMacc == nil { - panic(fmt.Sprintf("%s module account has not been set", SavingsRateMacc)) - } // validate denoms - check that any collaterals in the params are in the pricefeed, // pricefeed MUST call InitGenesis before cdp @@ -57,11 +53,16 @@ func InitGenesis(ctx sdk.Context, k Keeper, pk types.PricefeedKeeper, sk types.S k.SetParams(ctx, gs.Params) - // set the per second fee rate for each collateral type - for _, cp := range gs.Params.CollateralParams { - k.SetTotalPrincipal(ctx, cp.Type, gs.Params.DebtParam.Denom, sdk.ZeroInt()) + for _, gat := range gs.PreviousAccumulationTimes { + k.SetInterestFactor(ctx, gat.CollateralType, gat.InterestFactor) + if !gat.PreviousAccumulationTime.IsZero() { + k.SetPreviousAccrualTime(ctx, gat.CollateralType, gat.PreviousAccumulationTime) + } } + for _, gtp := range gs.TotalPrincipals { + k.SetTotalPrincipal(ctx, gtp.CollateralType, types.DefaultStableDenom, gtp.TotalPrincipal) + } // add cdps for _, cdp := range gs.CDPs { if cdp.ID == gs.StartingCdpID { @@ -74,22 +75,16 @@ func InitGenesis(ctx sdk.Context, k Keeper, pk types.PricefeedKeeper, sk types.S k.IndexCdpByOwner(ctx, cdp) ratio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Type, cdp.GetTotalPrincipal()) k.IndexCdpByCollateralRatio(ctx, cdp.Type, cdp.ID, ratio) - k.IncrementTotalPrincipal(ctx, cdp.Type, cdp.GetTotalPrincipal()) } k.SetNextCdpID(ctx, gs.StartingCdpID) k.SetDebtDenom(ctx, gs.DebtDenom) k.SetGovDenom(ctx, gs.GovDenom) - // only set the previous block time if it's different than default - if !gs.PreviousDistributionTime.Equal(types.DefaultPreviousDistributionTime) { - k.SetPreviousSavingsDistribution(ctx, gs.PreviousDistributionTime) - } for _, d := range gs.Deposits { k.SetDeposit(ctx, d) } - k.SetSavingsRateDistributed(ctx, gs.SavingsRateDistributed) } // ExportGenesis export genesis state for cdp module @@ -110,12 +105,22 @@ func ExportGenesis(ctx sdk.Context, k Keeper) GenesisState { cdpID := k.GetNextCdpID(ctx) debtDenom := k.GetDebtDenom(ctx) govDenom := k.GetGovDenom(ctx) - savingsRateDist := k.GetSavingsRateDistributed(ctx) - previousDistributionTime, found := k.GetPreviousSavingsDistribution(ctx) - if !found { - previousDistributionTime = DefaultPreviousDistributionTime + var previousAccumTimes types.GenesisAccumulationTimes + var totalPrincipals types.GenesisTotalPrincipals + + for _, cp := range params.CollateralParams { + interestFactor, found := k.GetInterestFactor(ctx, cp.Type) + if !found { + interestFactor = sdk.OneDec() + } + previousAccumTime, _ := k.GetPreviousAccrualTime(ctx, cp.Type) + previousAccumTimes = append(previousAccumTimes, types.NewGenesisAccumulationTime(cp.Type, previousAccumTime, interestFactor)) + + tp := k.GetTotalPrincipal(ctx, cp.Type, types.DefaultStableDenom) + genTotalPrincipal := types.NewGenesisTotalPrincipal(cp.Type, tp) + totalPrincipals = append(totalPrincipals, genTotalPrincipal) } - return NewGenesisState(params, cdps, deposits, cdpID, debtDenom, govDenom, previousDistributionTime, savingsRateDist) + return NewGenesisState(params, cdps, deposits, cdpID, debtDenom, govDenom, previousAccumTimes, totalPrincipals) } diff --git a/x/cdp/genesis_test.go b/x/cdp/genesis_test.go index 947867eb..7e5716b8 100644 --- a/x/cdp/genesis_test.go +++ b/x/cdp/genesis_test.go @@ -22,14 +22,15 @@ type GenesisTestSuite struct { func (suite *GenesisTestSuite) TestInvalidGenState() { type args struct { - params cdp.Params - cdps cdp.CDPs - deposits cdp.Deposits - startingID uint64 - debtDenom string - govDenom string - prevDistTime time.Time - savingsRateDist sdk.Int + params cdp.Params + cdps cdp.CDPs + deposits cdp.Deposits + startingID uint64 + debtDenom string + govDenom string + savingsRateDist sdk.Int + genAccumTimes cdp.GenesisAccumulationTimes + genTotalPrincipals cdp.GenesisTotalPrincipals } type errArgs struct { expectPass bool @@ -48,13 +49,14 @@ func (suite *GenesisTestSuite) TestInvalidGenState() { { name: "empty debt denom", args: args{ - params: cdp.DefaultParams(), - cdps: cdp.CDPs{}, - deposits: cdp.Deposits{}, - debtDenom: "", - govDenom: cdp.DefaultGovDenom, - prevDistTime: cdp.DefaultPreviousDistributionTime, - savingsRateDist: cdp.DefaultSavingsRateDistributed, + params: cdp.DefaultParams(), + cdps: cdp.CDPs{}, + deposits: cdp.Deposits{}, + debtDenom: "", + govDenom: cdp.DefaultGovDenom, + savingsRateDist: cdp.DefaultSavingsRateDistributed, + genAccumTimes: cdp.DefaultGenesisState().PreviousAccumulationTimes, + genTotalPrincipals: cdp.DefaultGenesisState().TotalPrincipals, }, errArgs: errArgs{ expectPass: false, @@ -64,13 +66,14 @@ func (suite *GenesisTestSuite) TestInvalidGenState() { { name: "empty gov denom", args: args{ - params: cdp.DefaultParams(), - cdps: cdp.CDPs{}, - deposits: cdp.Deposits{}, - debtDenom: cdp.DefaultDebtDenom, - govDenom: "", - prevDistTime: cdp.DefaultPreviousDistributionTime, - savingsRateDist: cdp.DefaultSavingsRateDistributed, + params: cdp.DefaultParams(), + cdps: cdp.CDPs{}, + deposits: cdp.Deposits{}, + debtDenom: cdp.DefaultDebtDenom, + govDenom: "", + savingsRateDist: cdp.DefaultSavingsRateDistributed, + genAccumTimes: cdp.DefaultGenesisState().PreviousAccumulationTimes, + genTotalPrincipals: cdp.DefaultGenesisState().TotalPrincipals, }, errArgs: errArgs{ expectPass: false, @@ -78,48 +81,49 @@ func (suite *GenesisTestSuite) TestInvalidGenState() { }, }, { - name: "empty distribution time", + name: "interest factor below one", args: args{ - params: cdp.DefaultParams(), - cdps: cdp.CDPs{}, - deposits: cdp.Deposits{}, - debtDenom: cdp.DefaultDebtDenom, - govDenom: cdp.DefaultGovDenom, - prevDistTime: time.Time{}, - savingsRateDist: cdp.DefaultSavingsRateDistributed, + params: cdp.DefaultParams(), + cdps: cdp.CDPs{}, + deposits: cdp.Deposits{}, + debtDenom: cdp.DefaultDebtDenom, + govDenom: cdp.DefaultGovDenom, + savingsRateDist: sdk.NewInt(100), + genAccumTimes: cdp.GenesisAccumulationTimes{cdp.NewGenesisAccumulationTime("bnb-a", time.Time{}, sdk.OneDec().Sub(sdk.SmallestDec()))}, + genTotalPrincipals: cdp.DefaultGenesisState().TotalPrincipals, }, errArgs: errArgs{ expectPass: false, - contains: "previous distribution time not set", + contains: "interest factor should be ≥ 1.0", }, }, { - name: "negative savings rate distributed", + name: "negative total principal", args: args{ - params: cdp.DefaultParams(), - cdps: cdp.CDPs{}, - deposits: cdp.Deposits{}, - debtDenom: cdp.DefaultDebtDenom, - govDenom: cdp.DefaultGovDenom, - prevDistTime: cdp.DefaultPreviousDistributionTime, - savingsRateDist: sdk.NewInt(-100), + params: cdp.DefaultParams(), + cdps: cdp.CDPs{}, + deposits: cdp.Deposits{}, + debtDenom: cdp.DefaultDebtDenom, + govDenom: cdp.DefaultGovDenom, + savingsRateDist: sdk.NewInt(100), + genAccumTimes: cdp.DefaultGenesisState().PreviousAccumulationTimes, + genTotalPrincipals: cdp.GenesisTotalPrincipals{cdp.NewGenesisTotalPrincipal("bnb-a", sdk.NewInt(-1))}, }, errArgs: errArgs{ expectPass: false, - contains: "savings rate distributed should not be negative", + contains: "total principal should be positive", }, }, } for _, tc := range testCases { suite.Run(tc.name, func() { gs := cdp.NewGenesisState(tc.args.params, tc.args.cdps, tc.args.deposits, tc.args.startingID, - tc.args.debtDenom, tc.args.govDenom, tc.args.prevDistTime, tc.args.savingsRateDist) + tc.args.debtDenom, tc.args.govDenom, tc.args.genAccumTimes, tc.args.genTotalPrincipals) err := gs.Validate() if tc.errArgs.expectPass { suite.Require().NoError(err) } else { suite.Require().Error(err) - suite.T().Log(err) suite.Require().True(strings.Contains(err.Error(), tc.errArgs.contains)) } }) diff --git a/x/cdp/handler.go b/x/cdp/handler.go index 5a7e04ec..d1764e70 100644 --- a/x/cdp/handler.go +++ b/x/cdp/handler.go @@ -20,6 +20,8 @@ func NewHandler(k Keeper) sdk.Handler { return handleMsgDrawDebt(ctx, k, msg) case MsgRepayDebt: return handleMsgRepayDebt(ctx, k, msg) + case MsgLiquidate: + return handleMsgLiquidate(ctx, k, msg) default: return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", ModuleName, msg) } @@ -110,3 +112,19 @@ func handleMsgRepayDebt(ctx sdk.Context, k Keeper, msg MsgRepayDebt) (*sdk.Resul ) return &sdk.Result{Events: ctx.EventManager().Events()}, nil } + +func handleMsgLiquidate(ctx sdk.Context, k Keeper, msg MsgLiquidate) (*sdk.Result, error) { + err := k.AttemptKeeperLiquidation(ctx, msg.Keeper, msg.Borrower, msg.CollateralType) + if err != nil { + return nil, err + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Keeper.String()), + ), + ) + return &sdk.Result{Events: ctx.EventManager().Events()}, nil +} diff --git a/x/cdp/integration_test.go b/x/cdp/integration_test.go index f7dd060e..4ddef46e 100644 --- a/x/cdp/integration_test.go +++ b/x/cdp/integration_test.go @@ -9,6 +9,7 @@ import ( "github.com/kava-labs/kava/app" "github.com/kava-labs/kava/x/cdp" + "github.com/kava-labs/kava/x/cdp/types" "github.com/kava-labs/kava/x/pricefeed" ) @@ -40,25 +41,26 @@ func NewPricefeedGenState(asset string, price sdk.Dec) app.GenesisState { func NewCDPGenState(asset string, liquidationRatio sdk.Dec) app.GenesisState { cdpGenesis := cdp.GenesisState{ Params: cdp.Params{ - GlobalDebtLimit: sdk.NewInt64Coin("usdx", 1000000000000), - SurplusAuctionThreshold: cdp.DefaultSurplusThreshold, - SurplusAuctionLot: cdp.DefaultSurplusLot, - DebtAuctionThreshold: cdp.DefaultDebtThreshold, - DebtAuctionLot: cdp.DefaultDebtLot, - SavingsDistributionFrequency: cdp.DefaultSavingsDistributionFrequency, + GlobalDebtLimit: sdk.NewInt64Coin("usdx", 1000000000000), + SurplusAuctionThreshold: cdp.DefaultSurplusThreshold, + SurplusAuctionLot: cdp.DefaultSurplusLot, + DebtAuctionThreshold: cdp.DefaultDebtThreshold, + DebtAuctionLot: cdp.DefaultDebtLot, CollateralParams: cdp.CollateralParams{ { - Denom: asset, - Type: asset + "-a", - LiquidationRatio: liquidationRatio, - DebtLimit: sdk.NewInt64Coin("usdx", 1000000000000), - StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), // %5 apr - LiquidationPenalty: d("0.05"), - AuctionSize: i(1000000000), - Prefix: 0x20, - ConversionFactor: i(6), - SpotMarketID: asset + ":usd", - LiquidationMarketID: asset + ":usd", + Denom: asset, + Type: asset + "-a", + LiquidationRatio: liquidationRatio, + DebtLimit: sdk.NewInt64Coin("usdx", 1000000000000), + StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), // %5 apr + LiquidationPenalty: d("0.05"), + AuctionSize: i(1000000000), + Prefix: 0x20, + ConversionFactor: i(6), + SpotMarketID: asset + ":usd", + LiquidationMarketID: asset + ":usd", + KeeperRewardPercentage: d("0.01"), + CheckCollateralizationIndexCount: i(10), }, }, DebtParam: cdp.DebtParam{ @@ -66,14 +68,18 @@ func NewCDPGenState(asset string, liquidationRatio sdk.Dec) app.GenesisState { ReferenceAsset: "usd", ConversionFactor: i(6), DebtFloor: i(10000000), - SavingsRate: d("0.95"), }, }, - StartingCdpID: cdp.DefaultCdpStartingID, - DebtDenom: cdp.DefaultDebtDenom, - GovDenom: cdp.DefaultGovDenom, - CDPs: cdp.CDPs{}, - PreviousDistributionTime: cdp.DefaultPreviousDistributionTime, + StartingCdpID: cdp.DefaultCdpStartingID, + DebtDenom: cdp.DefaultDebtDenom, + GovDenom: cdp.DefaultGovDenom, + CDPs: cdp.CDPs{}, + PreviousAccumulationTimes: cdp.GenesisAccumulationTimes{ + cdp.NewGenesisAccumulationTime(asset+"-a", time.Time{}, sdk.OneDec()), + }, + TotalPrincipals: cdp.GenesisTotalPrincipals{ + cdp.NewGenesisTotalPrincipal(asset+"-a", sdk.ZeroInt()), + }, } return app.GenesisState{cdp.ModuleName: cdp.ModuleCdc.MustMarshalJSON(cdpGenesis)} } @@ -106,38 +112,41 @@ func NewPricefeedGenStateMulti() app.GenesisState { func NewCDPGenStateMulti() app.GenesisState { cdpGenesis := cdp.GenesisState{ Params: cdp.Params{ - GlobalDebtLimit: sdk.NewInt64Coin("usdx", 1000000000000), - SurplusAuctionThreshold: cdp.DefaultSurplusThreshold, - SurplusAuctionLot: cdp.DefaultSurplusLot, - DebtAuctionThreshold: cdp.DefaultDebtThreshold, - DebtAuctionLot: cdp.DefaultDebtLot, - SavingsDistributionFrequency: cdp.DefaultSavingsDistributionFrequency, + GlobalDebtLimit: sdk.NewInt64Coin("usdx", 1000000000000), + SurplusAuctionThreshold: cdp.DefaultSurplusThreshold, + SurplusAuctionLot: cdp.DefaultSurplusLot, + DebtAuctionThreshold: cdp.DefaultDebtThreshold, + DebtAuctionLot: cdp.DefaultDebtLot, CollateralParams: cdp.CollateralParams{ { - Denom: "xrp", - Type: "xrp-a", - LiquidationRatio: sdk.MustNewDecFromStr("2.0"), - DebtLimit: sdk.NewInt64Coin("usdx", 500000000000), - StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), // %5 apr - LiquidationPenalty: d("0.05"), - AuctionSize: i(7000000000), - Prefix: 0x20, - SpotMarketID: "xrp:usd", - LiquidationMarketID: "xrp:usd", - ConversionFactor: i(6), + Denom: "xrp", + Type: "xrp-a", + LiquidationRatio: sdk.MustNewDecFromStr("2.0"), + DebtLimit: sdk.NewInt64Coin("usdx", 500000000000), + StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), // %5 apr + LiquidationPenalty: d("0.05"), + AuctionSize: i(7000000000), + Prefix: 0x20, + SpotMarketID: "xrp:usd", + LiquidationMarketID: "xrp:usd", + KeeperRewardPercentage: d("0.01"), + CheckCollateralizationIndexCount: i(10), + ConversionFactor: i(6), }, { - Denom: "btc", - Type: "btc-a", - LiquidationRatio: sdk.MustNewDecFromStr("1.5"), - DebtLimit: sdk.NewInt64Coin("usdx", 500000000000), - StabilityFee: sdk.MustNewDecFromStr("1.000000000782997609"), // %2.5 apr - LiquidationPenalty: d("0.025"), - AuctionSize: i(10000000), - Prefix: 0x21, - SpotMarketID: "btc:usd", - LiquidationMarketID: "btc:usd", - ConversionFactor: i(8), + Denom: "btc", + Type: "btc-a", + LiquidationRatio: sdk.MustNewDecFromStr("1.5"), + DebtLimit: sdk.NewInt64Coin("usdx", 500000000000), + StabilityFee: sdk.MustNewDecFromStr("1.000000000782997609"), // %2.5 apr + LiquidationPenalty: d("0.025"), + AuctionSize: i(10000000), + Prefix: 0x21, + SpotMarketID: "btc:usd", + LiquidationMarketID: "btc:usd", + KeeperRewardPercentage: d("0.01"), + CheckCollateralizationIndexCount: i(10), + ConversionFactor: i(8), }, }, DebtParam: cdp.DebtParam{ @@ -145,24 +154,30 @@ func NewCDPGenStateMulti() app.GenesisState { ReferenceAsset: "usd", ConversionFactor: i(6), DebtFloor: i(10000000), - SavingsRate: d("0.95"), }, }, - StartingCdpID: cdp.DefaultCdpStartingID, - DebtDenom: cdp.DefaultDebtDenom, - GovDenom: cdp.DefaultGovDenom, - CDPs: cdp.CDPs{}, - PreviousDistributionTime: cdp.DefaultPreviousDistributionTime, + StartingCdpID: cdp.DefaultCdpStartingID, + DebtDenom: cdp.DefaultDebtDenom, + GovDenom: cdp.DefaultGovDenom, + CDPs: cdp.CDPs{}, + PreviousAccumulationTimes: cdp.GenesisAccumulationTimes{ + cdp.NewGenesisAccumulationTime("btc-a", time.Time{}, sdk.OneDec()), + cdp.NewGenesisAccumulationTime("xrp-a", time.Time{}, sdk.OneDec()), + }, + TotalPrincipals: types.GenesisTotalPrincipals{ + cdp.NewGenesisTotalPrincipal("btc-a", sdk.ZeroInt()), + cdp.NewGenesisTotalPrincipal("xrp-a", sdk.ZeroInt()), + }, } return app.GenesisState{cdp.ModuleName: cdp.ModuleCdc.MustMarshalJSON(cdpGenesis)} } func cdps() (cdps cdp.CDPs) { _, addrs := app.GeneratePrivKeyAddressPairs(3) - c1 := cdp.NewCDP(uint64(1), addrs[0], sdk.NewCoin("xrp", sdk.NewInt(100000000)), "xrp-a", sdk.NewCoin("usdx", sdk.NewInt(8000000)), tmtime.Canonical(time.Now())) - c2 := cdp.NewCDP(uint64(2), addrs[1], sdk.NewCoin("xrp", sdk.NewInt(100000000)), "xrp-a", sdk.NewCoin("usdx", sdk.NewInt(10000000)), tmtime.Canonical(time.Now())) - c3 := cdp.NewCDP(uint64(3), addrs[1], sdk.NewCoin("btc", sdk.NewInt(1000000000)), "btc-a", sdk.NewCoin("usdx", sdk.NewInt(10000000)), tmtime.Canonical(time.Now())) - c4 := cdp.NewCDP(uint64(4), addrs[2], sdk.NewCoin("xrp", sdk.NewInt(1000000000)), "xrp-a", sdk.NewCoin("usdx", sdk.NewInt(50000000)), tmtime.Canonical(time.Now())) + c1 := cdp.NewCDP(uint64(1), addrs[0], sdk.NewCoin("xrp", sdk.NewInt(100000000)), "xrp-a", sdk.NewCoin("usdx", sdk.NewInt(8000000)), tmtime.Canonical(time.Now()), sdk.OneDec()) + c2 := cdp.NewCDP(uint64(2), addrs[1], sdk.NewCoin("xrp", sdk.NewInt(100000000)), "xrp-a", sdk.NewCoin("usdx", sdk.NewInt(10000000)), tmtime.Canonical(time.Now()), sdk.OneDec()) + c3 := cdp.NewCDP(uint64(3), addrs[1], sdk.NewCoin("btc", sdk.NewInt(1000000000)), "btc-a", sdk.NewCoin("usdx", sdk.NewInt(10000000)), tmtime.Canonical(time.Now()), sdk.OneDec()) + c4 := cdp.NewCDP(uint64(4), addrs[2], sdk.NewCoin("xrp", sdk.NewInt(1000000000)), "xrp-a", sdk.NewCoin("usdx", sdk.NewInt(50000000)), tmtime.Canonical(time.Now()), sdk.OneDec()) cdps = append(cdps, c1, c2, c3, c4) return } diff --git a/x/cdp/keeper/cdp.go b/x/cdp/keeper/cdp.go index 72e99dba..d1378468 100644 --- a/x/cdp/keeper/cdp.go +++ b/x/cdp/keeper/cdp.go @@ -11,9 +11,6 @@ import ( "github.com/kava-labs/kava/x/cdp/types" ) -// BaseDigitFactor is 10**18, used during coin calculations -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.Coin, principal sdk.Coin, collateralType string) error { // validation @@ -21,6 +18,10 @@ func (k Keeper) AddCdp(ctx sdk.Context, owner sdk.AccAddress, collateral sdk.Coi if err != nil { return err } + err = k.ValidateBalance(ctx, collateral, owner) + if err != nil { + return err + } _, found := k.GetCdpByOwnerAndCollateralType(ctx, owner, collateralType) if found { return sdkerrors.Wrapf(types.ErrCdpAlreadyExists, "owner %s, denom %s", owner, collateral.Denom) @@ -41,7 +42,13 @@ func (k Keeper) AddCdp(ctx sdk.Context, owner sdk.AccAddress, collateral sdk.Coi // send coins from the owners account to the cdp module id := k.GetNextCdpID(ctx) - cdp := types.NewCDP(id, owner, collateral, collateralType, principal, ctx.BlockHeader().Time) + interestFactor, found := k.GetInterestFactor(ctx, collateralType) + if !found { + interestFactor = sdk.OneDec() + k.SetInterestFactor(ctx, collateralType, interestFactor) + + } + cdp := types.NewCDP(id, owner, collateral, collateralType, principal, ctx.BlockHeader().Time, interestFactor) deposit := types.NewDeposit(cdp.ID, owner, collateral) err = k.supplyKeeper.SendCoinsFromAccountToModule(ctx, owner, types.ModuleName, sdk.NewCoins(collateral)) if err != nil { @@ -77,6 +84,8 @@ func (k Keeper) AddCdp(ctx sdk.Context, owner sdk.AccAddress, collateral sdk.Coi k.SetDeposit(ctx, deposit) k.SetNextCdpID(ctx, id+1) + k.hooks.AfterCDPCreated(ctx, cdp) + // emit events for cdp creation, deposit, and draw ctx.EventManager().EmitEvent( sdk.NewEvent( @@ -102,6 +111,31 @@ func (k Keeper) AddCdp(ctx sdk.Context, owner sdk.AccAddress, collateral sdk.Coi return nil } +// UpdateCdpAndCollateralRatioIndex updates the state of an existing cdp in the store by replacing the old index values and updating the store to the latest cdp object values +func (k Keeper) UpdateCdpAndCollateralRatioIndex(ctx sdk.Context, cdp types.CDP, ratio sdk.Dec) error { + err := k.removeOldCollateralRatioIndex(ctx, cdp.Type, cdp.ID) + if err != nil { + return err + } + + err = k.SetCDP(ctx, cdp) + if err != nil { + return err + } + k.IndexCdpByCollateralRatio(ctx, cdp.Type, cdp.ID, ratio) + return nil +} + +// DeleteCdpAndCollateralRatioIndex deletes an existing cdp in the store by removing the old index value and deleting the cdp object from the store +func (k Keeper) DeleteCdpAndCollateralRatioIndex(ctx sdk.Context, cdp types.CDP) error { + err := k.removeOldCollateralRatioIndex(ctx, cdp.Type, cdp.ID) + if err != nil { + return err + } + + return k.DeleteCDP(ctx, cdp) +} + // SetCdpAndCollateralRatioIndex sets the cdp and collateral ratio index in the store func (k Keeper) SetCdpAndCollateralRatioIndex(ctx sdk.Context, cdp types.CDP, ratio sdk.Dec) error { err := k.SetCDP(ctx, cdp) @@ -112,6 +146,16 @@ func (k Keeper) SetCdpAndCollateralRatioIndex(ctx sdk.Context, cdp types.CDP, ra return nil } +func (k Keeper) removeOldCollateralRatioIndex(ctx sdk.Context, ctype string, id uint64) error { + storedCDP, found := k.GetCDP(ctx, ctype, id) + if !found { + return sdkerrors.Wrapf(types.ErrCdpNotFound, "%d", storedCDP.ID) + } + oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, storedCDP.Collateral, storedCDP.Type, storedCDP.GetTotalPrincipal()) + k.RemoveCdpCollateralRatioIndex(ctx, storedCDP.Type, storedCDP.ID, oldCollateralToDebtRatio) + return nil +} + // MintDebtCoins mints debt coins in the cdp module account func (k Keeper) MintDebtCoins(ctx sdk.Context, moduleAccount string, denom string, principalCoins sdk.Coin) error { debtCoins := sdk.NewCoins(sdk.NewCoin(denom, principalCoins.Amount)) @@ -120,7 +164,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.Coin) error { - debtCoins := sdk.NewCoins(sdk.NewCoin(denom, paymentCoins.Amount)) + macc := k.supplyKeeper.GetModuleAccount(ctx, moduleAccount) + maxBurnableAmount := macc.GetCoins().AmountOf(denom) + // check that the requested burn is not greater than the mod account balance + debtCoins := sdk.NewCoins(sdk.NewCoin(denom, sdk.MinInt(paymentCoins.Amount, maxBurnableAmount))) return k.supplyKeeper.BurnCoins(ctx, moduleAccount, debtCoins) } @@ -419,6 +466,20 @@ func (k Keeper) ValidateCollateralizationRatio(ctx sdk.Context, collateral sdk.C return nil } +// ValidateBalance validates that the input account has sufficient spendable funds +func (k Keeper) ValidateBalance(ctx sdk.Context, amount sdk.Coin, sender sdk.AccAddress) error { + acc := k.accountKeeper.GetAccount(ctx, sender) + if acc == nil { + return sdkerrors.Wrapf(types.ErrAccountNotFound, "address: %s", sender) + } + spendableBalance := acc.SpendableCoins(ctx.BlockTime()).AmountOf(amount.Denom) + if spendableBalance.LT(amount.Amount) { + return sdkerrors.Wrapf(types.ErrInsufficientBalance, "%s < %s", sdk.NewCoin(amount.Denom, spendableBalance), amount) + } + + return nil +} + // CalculateCollateralToDebtRatio returns the collateral to debt ratio of the input collateral and debt amounts func (k Keeper) CalculateCollateralToDebtRatio(ctx sdk.Context, collateral sdk.Coin, collateralType string, debt sdk.Coin) sdk.Dec { debtTotal := k.convertDebtToBaseUnits(ctx, debt) @@ -433,6 +494,9 @@ 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 { + // sync the latest interest of the cdp + interestAccumulated := k.CalculateNewInterest(ctx, cdp) + cdp.AccumulatedFees = cdp.AccumulatedFees.Add(interestAccumulated) // calculate collateralization ratio collateralizationRatio, err := k.CalculateCollateralizationRatio(ctx, cdp.Collateral, cdp.Type, cdp.Principal, cdp.AccumulatedFees, liquidation) if err != nil { diff --git a/x/cdp/keeper/cdp_test.go b/x/cdp/keeper/cdp_test.go index e3c754e6..8ab37534 100644 --- a/x/cdp/keeper/cdp_test.go +++ b/x/cdp/keeper/cdp_test.go @@ -131,7 +131,7 @@ func (suite *CdpTestSuite) TestGetNextCdpID() { func (suite *CdpTestSuite) TestGetSetCdp() { _, addrs := app.GeneratePrivKeyAddressPairs(1) - cdp := types.NewCDP(types.DefaultCdpStartingID, addrs[0], c("xrp", 1), "xrp-a", c("usdx", 1), tmtime.Canonical(time.Now())) + cdp := types.NewCDP(types.DefaultCdpStartingID, addrs[0], c("xrp", 1), "xrp-a", c("usdx", 1), tmtime.Canonical(time.Now()), sdk.OneDec()) err := suite.keeper.SetCDP(suite.ctx, cdp) suite.NoError(err) @@ -147,7 +147,7 @@ func (suite *CdpTestSuite) TestGetSetCdp() { func (suite *CdpTestSuite) TestGetSetCdpId() { _, addrs := app.GeneratePrivKeyAddressPairs(2) - cdp := types.NewCDP(types.DefaultCdpStartingID, addrs[0], c("xrp", 1), "xrp-a", c("usdx", 1), tmtime.Canonical(time.Now())) + cdp := types.NewCDP(types.DefaultCdpStartingID, addrs[0], c("xrp", 1), "xrp-a", c("usdx", 1), tmtime.Canonical(time.Now()), sdk.OneDec()) err := suite.keeper.SetCDP(suite.ctx, cdp) suite.NoError(err) suite.keeper.IndexCdpByOwner(suite.ctx, cdp) @@ -162,7 +162,7 @@ func (suite *CdpTestSuite) TestGetSetCdpId() { func (suite *CdpTestSuite) TestGetSetCdpByOwnerAndCollateralType() { _, addrs := app.GeneratePrivKeyAddressPairs(2) - cdp := types.NewCDP(types.DefaultCdpStartingID, addrs[0], c("xrp", 1), "xrp-a", c("usdx", 1), tmtime.Canonical(time.Now())) + cdp := types.NewCDP(types.DefaultCdpStartingID, addrs[0], c("xrp", 1), "xrp-a", c("usdx", 1), tmtime.Canonical(time.Now()), sdk.OneDec()) err := suite.keeper.SetCDP(suite.ctx, cdp) suite.NoError(err) suite.keeper.IndexCdpByOwner(suite.ctx, cdp) @@ -178,17 +178,17 @@ func (suite *CdpTestSuite) TestGetSetCdpByOwnerAndCollateralType() { func (suite *CdpTestSuite) TestCalculateCollateralToDebtRatio() { _, addrs := app.GeneratePrivKeyAddressPairs(1) - cdp := types.NewCDP(types.DefaultCdpStartingID, addrs[0], c("xrp", 3), "xrp-a", c("usdx", 1), tmtime.Canonical(time.Now())) + cdp := types.NewCDP(types.DefaultCdpStartingID, addrs[0], c("xrp", 3), "xrp-a", c("usdx", 1), tmtime.Canonical(time.Now()), sdk.OneDec()) cr := suite.keeper.CalculateCollateralToDebtRatio(suite.ctx, cdp.Collateral, cdp.Type, cdp.Principal) suite.Equal(sdk.MustNewDecFromStr("3.0"), cr) - cdp = types.NewCDP(types.DefaultCdpStartingID, addrs[0], c("xrp", 1), "xrp-a", c("usdx", 2), tmtime.Canonical(time.Now())) + cdp = types.NewCDP(types.DefaultCdpStartingID, addrs[0], c("xrp", 1), "xrp-a", c("usdx", 2), tmtime.Canonical(time.Now()), sdk.OneDec()) cr = suite.keeper.CalculateCollateralToDebtRatio(suite.ctx, cdp.Collateral, cdp.Type, cdp.Principal) suite.Equal(sdk.MustNewDecFromStr("0.5"), cr) } func (suite *CdpTestSuite) TestSetCdpByCollateralRatio() { _, addrs := app.GeneratePrivKeyAddressPairs(1) - cdp := types.NewCDP(types.DefaultCdpStartingID, addrs[0], c("xrp", 3), "xrp-a", c("usdx", 1), tmtime.Canonical(time.Now())) + cdp := types.NewCDP(types.DefaultCdpStartingID, addrs[0], c("xrp", 3), "xrp-a", c("usdx", 1), tmtime.Canonical(time.Now()), sdk.OneDec()) cr := suite.keeper.CalculateCollateralToDebtRatio(suite.ctx, cdp.Collateral, cdp.Type, cdp.Principal) suite.NotPanics(func() { suite.keeper.IndexCdpByCollateralRatio(suite.ctx, cdp.Type, cdp.ID, cr) }) } diff --git a/x/cdp/keeper/deposit.go b/x/cdp/keeper/deposit.go index 50378f02..09c5ad2a 100644 --- a/x/cdp/keeper/deposit.go +++ b/x/cdp/keeper/deposit.go @@ -21,6 +21,12 @@ func (k Keeper) DepositCollateral(ctx sdk.Context, owner, depositor sdk.AccAddre if !found { return sdkerrors.Wrapf(types.ErrCdpNotFound, "owner %s, collateral %s", owner, collateralType) } + err = k.ValidateBalance(ctx, collateral, depositor) + if err != nil { + return err + } + k.hooks.BeforeCDPModified(ctx, cdp) + cdp = k.SynchronizeInterest(ctx, cdp) deposit, found := k.GetDeposit(ctx, cdp.ID, depositor) if found { @@ -32,6 +38,12 @@ func (k Keeper) DepositCollateral(ctx sdk.Context, owner, depositor sdk.AccAddre if err != nil { return err } + + k.SetDeposit(ctx, deposit) + + cdp.Collateral = cdp.Collateral.Add(collateral) + collateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Type, cdp.GetTotalPrincipal()) + ctx.EventManager().EmitEvent( sdk.NewEvent( types.EventTypeCdpDeposit, @@ -40,14 +52,7 @@ func (k Keeper) DepositCollateral(ctx sdk.Context, owner, depositor sdk.AccAddre ), ) - k.SetDeposit(ctx, deposit) - - oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Type, cdp.GetTotalPrincipal()) - k.RemoveCdpCollateralRatioIndex(ctx, cdp.Type, cdp.ID, oldCollateralToDebtRatio) - - cdp.Collateral = cdp.Collateral.Add(collateral) - collateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Type, cdp.GetTotalPrincipal()) - return k.SetCdpAndCollateralRatioIndex(ctx, cdp, collateralToDebtRatio) + return k.UpdateCdpAndCollateralRatioIndex(ctx, cdp, collateralToDebtRatio) } // WithdrawCollateral removes collateral from a cdp if it does not put the cdp below the liquidation ratio @@ -67,6 +72,8 @@ func (k Keeper) WithdrawCollateral(ctx sdk.Context, owner, depositor sdk.AccAddr if collateral.Amount.GT(deposit.Amount.Amount) { return sdkerrors.Wrapf(types.ErrInvalidWithdrawAmount, "collateral %s, deposit %s", collateral, deposit.Amount) } + k.hooks.BeforeCDPModified(ctx, cdp) + cdp = k.SynchronizeInterest(ctx, cdp) collateralizationRatio, err := k.CalculateCollateralizationRatio(ctx, cdp.Collateral.Sub(collateral), cdp.Type, cdp.Principal, cdp.AccumulatedFees, spot) if err != nil { @@ -76,24 +83,15 @@ func (k Keeper) WithdrawCollateral(ctx sdk.Context, owner, depositor sdk.AccAddr if collateralizationRatio.LT(liquidationRatio) { return sdkerrors.Wrapf(types.ErrInvalidCollateralRatio, "collateral %s, collateral ratio %s, liquidation ration %s", collateral.Denom, collateralizationRatio, liquidationRatio) } - ctx.EventManager().EmitEvent( - sdk.NewEvent( - types.EventTypeCdpWithdrawal, - sdk.NewAttribute(sdk.AttributeKeyAmount, collateral.String()), - sdk.NewAttribute(types.AttributeKeyCdpID, fmt.Sprintf("%d", cdp.ID)), - ), - ) err = k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, depositor, sdk.NewCoins(collateral)) if err != nil { panic(err) } - oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Type, cdp.GetTotalPrincipal()) - k.RemoveCdpCollateralRatioIndex(ctx, cdp.Type, cdp.ID, oldCollateralToDebtRatio) cdp.Collateral = cdp.Collateral.Sub(collateral) collateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Type, cdp.GetTotalPrincipal()) - err = k.SetCdpAndCollateralRatioIndex(ctx, cdp, collateralToDebtRatio) + err = k.UpdateCdpAndCollateralRatioIndex(ctx, cdp, collateralToDebtRatio) if err != nil { return err } @@ -105,6 +103,15 @@ func (k Keeper) WithdrawCollateral(ctx sdk.Context, owner, depositor sdk.AccAddr } else { k.SetDeposit(ctx, deposit) } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeCdpWithdrawal, + sdk.NewAttribute(sdk.AttributeKeyAmount, collateral.String()), + sdk.NewAttribute(types.AttributeKeyCdpID, fmt.Sprintf("%d", cdp.ID)), + ), + ) + return nil } diff --git a/x/cdp/keeper/draw.go b/x/cdp/keeper/draw.go index 26086161..3fbc3d0f 100644 --- a/x/cdp/keeper/draw.go +++ b/x/cdp/keeper/draw.go @@ -25,6 +25,8 @@ func (k Keeper) AddPrincipal(ctx sdk.Context, owner sdk.AccAddress, collateralTy if err != nil { return err } + k.hooks.BeforeCDPModified(ctx, cdp) + cdp = k.SynchronizeInterest(ctx, cdp) err = k.ValidateCollateralizationRatio(ctx, cdp.Collateral, cdp.Type, cdp.Principal.Add(principal), cdp.AccumulatedFees) if err != nil { @@ -56,10 +58,6 @@ func (k Keeper) AddPrincipal(ctx sdk.Context, owner sdk.AccAddress, collateralTy ), ) - // remove old collateral:debt index - oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Type, cdp.GetTotalPrincipal()) - k.RemoveCdpCollateralRatioIndex(ctx, cdp.Type, cdp.ID, oldCollateralToDebtRatio) - // update cdp state cdp.Principal = cdp.Principal.Add(principal) @@ -68,7 +66,7 @@ func (k Keeper) AddPrincipal(ctx sdk.Context, owner sdk.AccAddress, collateralTy // set cdp state and indexes in the store collateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Type, cdp.GetTotalPrincipal()) - return k.SetCdpAndCollateralRatioIndex(ctx, cdp, collateralToDebtRatio) + return k.UpdateCdpAndCollateralRatioIndex(ctx, cdp, collateralToDebtRatio) } // RepayPrincipal removes debt from the cdp @@ -85,6 +83,13 @@ func (k Keeper) RepayPrincipal(ctx sdk.Context, owner sdk.AccAddress, collateral return err } + err = k.ValidateBalance(ctx, payment, owner) + if err != nil { + return err + } + k.hooks.BeforeCDPModified(ctx, cdp) + cdp = k.SynchronizeInterest(ctx, cdp) + // Note: assumes cdp.Principal and cdp.AccumulatedFees don't change during calculations totalPrincipal := cdp.GetTotalPrincipal() @@ -134,8 +139,6 @@ func (k Keeper) RepayPrincipal(ctx sdk.Context, owner sdk.AccAddress, collateral ) // remove the old collateral:debt ratio index - oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Type, totalPrincipal) - k.RemoveCdpCollateralRatioIndex(ctx, cdp.Type, cdp.ID, oldCollateralToDebtRatio) // update cdp state if !principalPayment.IsZero() { @@ -150,12 +153,12 @@ func (k Keeper) RepayPrincipal(ctx sdk.Context, owner sdk.AccAddress, collateral // and remove the cdp and indexes from the store if cdp.Principal.IsZero() && cdp.AccumulatedFees.IsZero() { k.ReturnCollateral(ctx, cdp) - if err := k.DeleteCDP(ctx, cdp); err != nil { + k.RemoveCdpOwnerIndex(ctx, cdp) + err := k.DeleteCdpAndCollateralRatioIndex(ctx, cdp) + if err != nil { return err } - k.RemoveCdpOwnerIndex(ctx, cdp) - // emit cdp close event ctx.EventManager().EmitEvent( sdk.NewEvent( @@ -168,7 +171,7 @@ func (k Keeper) RepayPrincipal(ctx sdk.Context, owner sdk.AccAddress, collateral // set cdp state and update indexes collateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Type, cdp.GetTotalPrincipal()) - return k.SetCdpAndCollateralRatioIndex(ctx, cdp, collateralToDebtRatio) + return k.UpdateCdpAndCollateralRatioIndex(ctx, cdp, collateralToDebtRatio) } // ValidatePaymentCoins validates that the input coins are valid for repaying debt diff --git a/x/cdp/keeper/draw_test.go b/x/cdp/keeper/draw_test.go index c1c066d9..e757935e 100644 --- a/x/cdp/keeper/draw_test.go +++ b/x/cdp/keeper/draw_test.go @@ -129,37 +129,6 @@ func (suite *DrawTestSuite) TestRepayPrincipalOverpay() { suite.False(found) } -func (suite *DrawTestSuite) TestAddRepayPrincipalFees() { - err := suite.keeper.AddCdp(suite.ctx, suite.addrs[2], c("xrp", 1000000000000), c("usdx", 100000000000), "xrp-a") - suite.NoError(err) - suite.ctx = suite.ctx.WithBlockTime(suite.ctx.BlockTime().Add(time.Minute * 10)) - err = suite.keeper.UpdateFeesForAllCdps(suite.ctx, "xrp-a") - suite.NoError(err) - err = suite.keeper.AddPrincipal(suite.ctx, suite.addrs[2], "xrp-a", c("usdx", 10000000)) - suite.NoError(err) - t, _ := suite.keeper.GetCDP(suite.ctx, "xrp-a", uint64(2)) - suite.Equal(c("usdx", 92827), t.AccumulatedFees) - err = suite.keeper.RepayPrincipal(suite.ctx, suite.addrs[2], "xrp-a", c("usdx", 100)) - suite.NoError(err) - t, _ = suite.keeper.GetCDP(suite.ctx, "xrp-a", uint64(2)) - suite.Equal(c("usdx", 92727), t.AccumulatedFees) - err = suite.keeper.RepayPrincipal(suite.ctx, suite.addrs[2], "xrp-a", c("usdx", 100010092727)) - suite.NoError(err) - _, f := suite.keeper.GetCDP(suite.ctx, "xrp-a", uint64(2)) - suite.False(f) - - err = suite.keeper.AddCdp(suite.ctx, suite.addrs[2], c("xrp", 1000000000000), c("usdx", 100000000), "xrp-a") - suite.NoError(err) - - suite.ctx = suite.ctx.WithBlockTime(suite.ctx.BlockTime().Add(time.Second * 31536000)) // move forward one year in time - err = suite.keeper.UpdateFeesForAllCdps(suite.ctx, "xrp-a") - suite.NoError(err) - err = suite.keeper.AddPrincipal(suite.ctx, suite.addrs[2], "xrp-a", c("usdx", 100000000)) - suite.NoError(err) - t, _ = suite.keeper.GetCDP(suite.ctx, "xrp-a", uint64(3)) - suite.Equal(c("usdx", 5000000), t.AccumulatedFees) -} - func (suite *DrawTestSuite) TestPricefeedFailure() { ctx := suite.ctx.WithBlockTime(suite.ctx.BlockTime().Add(time.Hour * 2)) pfk := suite.app.GetPriceFeedKeeper() diff --git a/x/cdp/keeper/fees.go b/x/cdp/keeper/fees.go deleted file mode 100644 index f9982617..00000000 --- a/x/cdp/keeper/fees.go +++ /dev/null @@ -1,137 +0,0 @@ -package keeper - -import ( - "fmt" - - "github.com/cosmos/cosmos-sdk/store/prefix" - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/kava-labs/kava/x/cdp/types" -) - -// CalculateFees returns the fees accumulated since fees were last calculated based on -// the input amount of outstanding debt (principal) and the number of periods (seconds) that have passed -func (k Keeper) CalculateFees(ctx sdk.Context, principal sdk.Coin, periods sdk.Int, collateralType string) sdk.Coin { - // how fees are calculated: - // feesAccumulated = (outstandingDebt * (feeRate^periods)) - outstandingDebt - // Note that since we can't do x^y using sdk.Decimal, we are converting to int and using RelativePow - feePerSecond := k.getFeeRate(ctx, collateralType) - scalar := sdk.NewInt(1000000000000000000) - feeRateInt := feePerSecond.Mul(sdk.NewDecFromInt(scalar)).TruncateInt() - accumulator := sdk.NewDecFromInt(types.RelativePow(feeRateInt, periods, scalar)).Mul(sdk.SmallestDec()) - feesAccumulated := (sdk.NewDecFromInt(principal.Amount).Mul(accumulator)).Sub(sdk.NewDecFromInt(principal.Amount)) - newFees := sdk.NewCoin(principal.Denom, feesAccumulated.TruncateInt()) - return newFees -} - -// UpdateFeesForAllCdps updates the fees for each of the CDPs -func (k Keeper) UpdateFeesForAllCdps(ctx sdk.Context, collateralType string) error { - var iterationErr error - k.IterateCdpsByCollateralType(ctx, collateralType, func(cdp types.CDP) bool { - oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Type, cdp.GetTotalPrincipal()) - // periods = bblock timestamp - fees updated - periods := sdk.NewInt(ctx.BlockTime().Unix()).Sub(sdk.NewInt(cdp.FeesUpdated.Unix())) - - newFees := k.CalculateFees(ctx, cdp.Principal, periods, collateralType) - - // exit without updating fees if amount has rounded down to zero - // cdp will get updated next block when newFees, newFeesSavings, newFeesSurplus >0 - if newFees.IsZero() { - return false - } - - dp, found := k.GetDebtParam(ctx, cdp.Principal.Denom) - if !found { - return false - } - savingsRate := dp.SavingsRate - - newFeesSavings := sdk.NewDecFromInt(newFees.Amount).Mul(savingsRate).RoundInt() - newFeesSurplus := newFees.Amount.Sub(newFeesSavings) - - // similar to checking for rounding to zero of all fees, but in this case we - // need to handle cases where we expect surplus or savings fees to be zero, namely - // if newFeesSavings = 0, check if savings rate is not zero - // if newFeesSurplus = 0, check if savings rate is not one - if (newFeesSavings.IsZero() && !savingsRate.IsZero()) || (newFeesSurplus.IsZero() && !savingsRate.Equal(sdk.OneDec())) { - return false - } - - // mint debt coins to the cdp account - err := k.MintDebtCoins(ctx, types.ModuleName, k.GetDebtDenom(ctx), newFees) - if err != nil { - iterationErr = err - return true - } - - previousDebt := k.GetTotalPrincipal(ctx, cdp.Type, dp.Denom) - newDebt := previousDebt.Add(newFees.Amount) - k.SetTotalPrincipal(ctx, cdp.Type, dp.Denom, newDebt) - - // mint surplus coins divided between the liquidator and savings module accounts. - err = k.supplyKeeper.MintCoins(ctx, types.LiquidatorMacc, sdk.NewCoins(sdk.NewCoin(dp.Denom, newFeesSurplus))) - if err != nil { - iterationErr = err - return true - } - - err = k.supplyKeeper.MintCoins(ctx, types.SavingsRateMacc, sdk.NewCoins(sdk.NewCoin(dp.Denom, newFeesSavings))) - if err != nil { - iterationErr = err - return true - } - - // now add the new fees to the accumulated fees for the cdp - cdp.AccumulatedFees = cdp.AccumulatedFees.Add(newFees) - - // 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.Type, cdp.GetTotalPrincipal()) - k.RemoveCdpCollateralRatioIndex(ctx, cdp.Type, cdp.ID, oldCollateralToDebtRatio) - err = k.SetCdpAndCollateralRatioIndex(ctx, cdp, collateralToDebtRatio) - if err != nil { - iterationErr = err - return true - } - return false // this returns true when you want to stop iterating. Since we want to iterate through all we return false - }) - return iterationErr -} - -// IncrementTotalPrincipal increments the total amount of debt that has been drawn with that collateral type -func (k Keeper) IncrementTotalPrincipal(ctx sdk.Context, collateralType string, principal sdk.Coin) { - total := k.GetTotalPrincipal(ctx, collateralType, principal.Denom) - total = total.Add(principal.Amount) - k.SetTotalPrincipal(ctx, collateralType, principal.Denom, total) -} - -// DecrementTotalPrincipal decrements the total amount of debt that has been drawn for a particular collateral type -func (k Keeper) DecrementTotalPrincipal(ctx sdk.Context, collateralType string, principal sdk.Coin) { - total := k.GetTotalPrincipal(ctx, collateralType, principal.Denom) - // NOTE: negative total principal can happen in tests due to rounding errors - // in fee calculation - total = sdk.MaxInt(total.Sub(principal.Amount), sdk.ZeroInt()) - k.SetTotalPrincipal(ctx, collateralType, principal.Denom, total) -} - -// GetTotalPrincipal returns the total amount of principal that has been drawn for a particular collateral -func (k Keeper) GetTotalPrincipal(ctx sdk.Context, collateralType, principalDenom string) (total sdk.Int) { - store := prefix.NewStore(ctx.KVStore(k.key), types.PrincipalKeyPrefix) - bz := store.Get([]byte(collateralType + principalDenom)) - if bz == nil { - k.SetTotalPrincipal(ctx, collateralType, principalDenom, sdk.ZeroInt()) - return sdk.ZeroInt() - } - k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &total) - return total -} - -// SetTotalPrincipal sets the total amount of principal that has been drawn for the input collateral -func (k Keeper) SetTotalPrincipal(ctx sdk.Context, collateralType, principalDenom string, total sdk.Int) { - store := prefix.NewStore(ctx.KVStore(k.key), types.PrincipalKeyPrefix) - _, found := k.GetCollateralTypePrefix(ctx, collateralType) - if !found { - panic(fmt.Sprintf("collateral not found: %s", collateralType)) - } - store.Set([]byte(collateralType+principalDenom), k.cdc.MustMarshalBinaryLengthPrefixed(total)) -} diff --git a/x/cdp/keeper/fees_test.go b/x/cdp/keeper/fees_test.go deleted file mode 100644 index ef6951d4..00000000 --- a/x/cdp/keeper/fees_test.go +++ /dev/null @@ -1,101 +0,0 @@ -package keeper_test - -import ( - "testing" - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/stretchr/testify/suite" - - abci "github.com/tendermint/tendermint/abci/types" - tmtime "github.com/tendermint/tendermint/types/time" - - "github.com/kava-labs/kava/app" - "github.com/kava-labs/kava/x/cdp/keeper" -) - -type FeeTestSuite struct { - suite.Suite - - keeper keeper.Keeper - app app.TestApp - ctx sdk.Context -} - -func (suite *FeeTestSuite) SetupTest() { - tApp := app.NewTestApp() - ctx := tApp.NewContext(true, abci.Header{Height: 1, Time: tmtime.Now()}) - tApp.InitializeFromGenesisStates( - NewPricefeedGenStateMulti(), - NewCDPGenStateMulti(), - ) - keeper := tApp.GetCDPKeeper() - suite.app = tApp - suite.ctx = ctx - suite.keeper = keeper -} - -// createCdps is a helper function to create two CDPs each with zero fees -func (suite *FeeTestSuite) createCdps() { - // create 2 accounts in the state and give them some coins - // create two private key pair addresses - _, addrs := app.GeneratePrivKeyAddressPairs(2) - ak := suite.app.GetAccountKeeper() - // setup the first account - acc := ak.NewAccountWithAddress(suite.ctx, addrs[0]) - acc.SetCoins(cs(c("xrp", 200000000), c("btc", 500000000))) - - ak.SetAccount(suite.ctx, acc) - // now setup the second account - acc2 := ak.NewAccountWithAddress(suite.ctx, addrs[1]) - acc2.SetCoins(cs(c("xrp", 200000000), c("btc", 500000000))) - ak.SetAccount(suite.ctx, acc2) - - // now create two cdps with the addresses we just created - // use the created account to create a cdp that SHOULD have fees updated - // to get a ratio between 100 - 110% of liquidation ratio we can use 200xrp ($50) and 24 usdx (208% collateralization with liquidation ratio of 200%) - // create CDP for the first address - err := suite.keeper.AddCdp(suite.ctx, addrs[0], c("xrp", 200000000), c("usdx", 24000000), "xrp-a") - suite.NoError(err) // check that no error was thrown - - // use the other account to create a cdp that SHOULD NOT have fees updated - 500% collateralization - // create CDP for the second address - err = suite.keeper.AddCdp(suite.ctx, addrs[1], c("xrp", 200000000), c("usdx", 10000000), "xrp-a") - suite.NoError(err) // check that no error was thrown - -} - -// TestUpdateFees tests the functionality for updating the fees for CDPs -func (suite *FeeTestSuite) TestUpdateFees() { - // this helper function creates two CDPs with id 1 and 2 respectively, each with zero fees - suite.createCdps() - - // move the context forward in time so that cdps will have fees accumulate if CalculateFees is called - // note - time must be moved forward by a sufficient amount in order for additional - // fees to accumulate, in this example 600 seconds - oldtime := suite.ctx.BlockTime() - suite.ctx = suite.ctx.WithBlockTime(suite.ctx.BlockTime().Add(time.Second * 600)) - err := suite.keeper.UpdateFeesForAllCdps(suite.ctx, "xrp-a") - suite.NoError(err) // check that we don't have any error - - // cdp we expect fees to accumulate for - cdp1, found := suite.keeper.GetCDP(suite.ctx, "xrp-a", 1) - suite.True(found) - // check fees are not zero - // check that the fees have been updated - suite.False(cdp1.AccumulatedFees.IsZero()) - // now check that we have the correct amount of fees overall (22 USDX for this scenario) - suite.Equal(sdk.NewInt(22), cdp1.AccumulatedFees.Amount) - suite.Equal(suite.ctx.BlockTime(), cdp1.FeesUpdated) - // cdp we expect fees to not accumulate for because of rounding to zero - cdp2, found := suite.keeper.GetCDP(suite.ctx, "xrp-a", 2) - suite.True(found) - // check fees are zero - suite.True(cdp2.AccumulatedFees.IsZero()) - suite.Equal(oldtime, cdp2.FeesUpdated) -} - -func TestFeeTestSuite(t *testing.T) { - suite.Run(t, new(FeeTestSuite)) -} diff --git a/x/cdp/keeper/hooks.go b/x/cdp/keeper/hooks.go new file mode 100644 index 00000000..7768bc08 --- /dev/null +++ b/x/cdp/keeper/hooks.go @@ -0,0 +1,23 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/kava-labs/kava/x/cdp/types" +) + +// Implements StakingHooks interface +var _ types.CDPHooks = Keeper{} + +// AfterCDPCreated - call hook if registered +func (k Keeper) AfterCDPCreated(ctx sdk.Context, cdp types.CDP) { + if k.hooks != nil { + k.hooks.AfterCDPCreated(ctx, cdp) + } +} + +// BeforeCDPModified - call hook if registered +func (k Keeper) BeforeCDPModified(ctx sdk.Context, cdp types.CDP) { + if k.hooks != nil { + k.hooks.BeforeCDPModified(ctx, cdp) + } +} diff --git a/x/cdp/keeper/integration_test.go b/x/cdp/keeper/integration_test.go index f7adaff1..1cf18184 100644 --- a/x/cdp/keeper/integration_test.go +++ b/x/cdp/keeper/integration_test.go @@ -40,25 +40,26 @@ func NewPricefeedGenState(asset string, price sdk.Dec) app.GenesisState { func NewCDPGenState(asset string, liquidationRatio sdk.Dec) app.GenesisState { cdpGenesis := cdp.GenesisState{ Params: cdp.Params{ - GlobalDebtLimit: sdk.NewInt64Coin("usdx", 1000000000000), - SurplusAuctionThreshold: cdp.DefaultSurplusThreshold, - SurplusAuctionLot: cdp.DefaultSurplusLot, - DebtAuctionThreshold: cdp.DefaultDebtThreshold, - DebtAuctionLot: cdp.DefaultDebtLot, - SavingsDistributionFrequency: cdp.DefaultSavingsDistributionFrequency, + GlobalDebtLimit: sdk.NewInt64Coin("usdx", 1000000000000), + SurplusAuctionThreshold: cdp.DefaultSurplusThreshold, + SurplusAuctionLot: cdp.DefaultSurplusLot, + DebtAuctionThreshold: cdp.DefaultDebtThreshold, + DebtAuctionLot: cdp.DefaultDebtLot, CollateralParams: cdp.CollateralParams{ { - Denom: asset, - Type: asset + "-a", - LiquidationRatio: liquidationRatio, - DebtLimit: sdk.NewInt64Coin("usdx", 1000000000000), - StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), // %5 apr - LiquidationPenalty: d("0.05"), - AuctionSize: i(100), - Prefix: 0x20, - ConversionFactor: i(6), - SpotMarketID: asset + ":usd", - LiquidationMarketID: asset + ":usd", + Denom: asset, + Type: asset + "-a", + LiquidationRatio: liquidationRatio, + DebtLimit: sdk.NewInt64Coin("usdx", 1000000000000), + StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), // %5 apr + LiquidationPenalty: d("0.05"), + AuctionSize: i(100), + Prefix: 0x20, + SpotMarketID: asset + ":usd", + LiquidationMarketID: asset + ":usd", + KeeperRewardPercentage: d("0.01"), + CheckCollateralizationIndexCount: i(10), + ConversionFactor: i(6), }, }, DebtParam: cdp.DebtParam{ @@ -66,14 +67,18 @@ func NewCDPGenState(asset string, liquidationRatio sdk.Dec) app.GenesisState { ReferenceAsset: "usd", ConversionFactor: i(6), DebtFloor: i(10000000), - SavingsRate: d("0.9"), }, }, - StartingCdpID: cdp.DefaultCdpStartingID, - DebtDenom: cdp.DefaultDebtDenom, - GovDenom: cdp.DefaultGovDenom, - CDPs: cdp.CDPs{}, - PreviousDistributionTime: cdp.DefaultPreviousDistributionTime, + StartingCdpID: cdp.DefaultCdpStartingID, + DebtDenom: cdp.DefaultDebtDenom, + GovDenom: cdp.DefaultGovDenom, + CDPs: cdp.CDPs{}, + PreviousAccumulationTimes: cdp.GenesisAccumulationTimes{ + cdp.NewGenesisAccumulationTime(asset+"-a", time.Time{}, sdk.OneDec()), + }, + TotalPrincipals: cdp.GenesisTotalPrincipals{ + cdp.NewGenesisTotalPrincipal(asset+"-a", sdk.ZeroInt()), + }, } return app.GenesisState{cdp.ModuleName: cdp.ModuleCdc.MustMarshalJSON(cdpGenesis)} } @@ -85,6 +90,7 @@ func NewPricefeedGenStateMulti() app.GenesisState { {MarketID: "btc:usd", BaseAsset: "btc", QuoteAsset: "usd", Oracles: []sdk.AccAddress{}, Active: true}, {MarketID: "xrp:usd", BaseAsset: "xrp", QuoteAsset: "usd", Oracles: []sdk.AccAddress{}, Active: true}, {MarketID: "bnb:usd", BaseAsset: "bnb", QuoteAsset: "usd", Oracles: []sdk.AccAddress{}, Active: true}, + {MarketID: "busd:usd", BaseAsset: "busd", QuoteAsset: "usd", Oracles: []sdk.AccAddress{}, Active: true}, }, }, PostedPrices: []pricefeed.PostedPrice{ @@ -106,6 +112,12 @@ func NewPricefeedGenStateMulti() app.GenesisState { Price: sdk.MustNewDecFromStr("17.25"), Expiry: time.Now().Add(1 * time.Hour), }, + { + MarketID: "busd:usd", + OracleAddress: sdk.AccAddress{}, + Price: sdk.OneDec(), + Expiry: time.Now().Add(1 * time.Hour), + }, }, } return app.GenesisState{pricefeed.ModuleName: pricefeed.ModuleCdc.MustMarshalJSON(pfGenesis)} @@ -113,51 +125,71 @@ func NewPricefeedGenStateMulti() app.GenesisState { func NewCDPGenStateMulti() app.GenesisState { cdpGenesis := cdp.GenesisState{ Params: cdp.Params{ - GlobalDebtLimit: sdk.NewInt64Coin("usdx", 1500000000000), - SurplusAuctionThreshold: cdp.DefaultSurplusThreshold, - SurplusAuctionLot: cdp.DefaultSurplusLot, - DebtAuctionThreshold: cdp.DefaultDebtThreshold, - DebtAuctionLot: cdp.DefaultDebtLot, - SavingsDistributionFrequency: cdp.DefaultSavingsDistributionFrequency, + GlobalDebtLimit: sdk.NewInt64Coin("usdx", 2000000000000), + SurplusAuctionThreshold: cdp.DefaultSurplusThreshold, + SurplusAuctionLot: cdp.DefaultSurplusLot, + DebtAuctionThreshold: cdp.DefaultDebtThreshold, + DebtAuctionLot: cdp.DefaultDebtLot, CollateralParams: cdp.CollateralParams{ { - Denom: "xrp", - Type: "xrp-a", - LiquidationRatio: sdk.MustNewDecFromStr("2.0"), - DebtLimit: sdk.NewInt64Coin("usdx", 500000000000), - StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), // %5 apr - LiquidationPenalty: d("0.05"), - AuctionSize: i(7000000000), - Prefix: 0x20, - SpotMarketID: "xrp:usd", - LiquidationMarketID: "xrp:usd", - ConversionFactor: i(6), + Denom: "xrp", + Type: "xrp-a", + LiquidationRatio: sdk.MustNewDecFromStr("2.0"), + DebtLimit: sdk.NewInt64Coin("usdx", 500000000000), + StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), // %5 apr + LiquidationPenalty: d("0.05"), + AuctionSize: i(7000000000), + Prefix: 0x20, + SpotMarketID: "xrp:usd", + LiquidationMarketID: "xrp:usd", + KeeperRewardPercentage: d("0.01"), + CheckCollateralizationIndexCount: i(10), + ConversionFactor: i(6), }, { - Denom: "btc", - Type: "btc-a", - LiquidationRatio: sdk.MustNewDecFromStr("1.5"), - DebtLimit: sdk.NewInt64Coin("usdx", 500000000000), - StabilityFee: sdk.MustNewDecFromStr("1.000000000782997609"), // %2.5 apr - LiquidationPenalty: d("0.025"), - AuctionSize: i(10000000), - Prefix: 0x21, - SpotMarketID: "btc:usd", - LiquidationMarketID: "btc:usd", - ConversionFactor: i(8), + Denom: "btc", + Type: "btc-a", + LiquidationRatio: sdk.MustNewDecFromStr("1.5"), + DebtLimit: sdk.NewInt64Coin("usdx", 500000000000), + StabilityFee: sdk.MustNewDecFromStr("1.000000000782997609"), // %2.5 apr + LiquidationPenalty: d("0.025"), + AuctionSize: i(10000000), + Prefix: 0x21, + SpotMarketID: "btc:usd", + LiquidationMarketID: "btc:usd", + KeeperRewardPercentage: d("0.01"), + CheckCollateralizationIndexCount: i(10), + ConversionFactor: i(8), }, { - Denom: "bnb", - Type: "bnb-a", - LiquidationRatio: sdk.MustNewDecFromStr("1.5"), - DebtLimit: sdk.NewInt64Coin("usdx", 500000000000), - StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), // %5 apr - LiquidationPenalty: d("0.05"), - AuctionSize: i(50000000000), - Prefix: 0x22, - SpotMarketID: "bnb:usd", - LiquidationMarketID: "bnb:usd", - ConversionFactor: i(8), + Denom: "bnb", + Type: "bnb-a", + LiquidationRatio: sdk.MustNewDecFromStr("1.5"), + DebtLimit: sdk.NewInt64Coin("usdx", 500000000000), + StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), // %5 apr + LiquidationPenalty: d("0.05"), + AuctionSize: i(50000000000), + Prefix: 0x22, + SpotMarketID: "bnb:usd", + LiquidationMarketID: "bnb:usd", + KeeperRewardPercentage: d("0.01"), + CheckCollateralizationIndexCount: i(10), + ConversionFactor: i(8), + }, + { + Denom: "busd", + Type: "busd-a", + LiquidationRatio: d("1.01"), + DebtLimit: sdk.NewInt64Coin("usdx", 500000000000), + StabilityFee: sdk.OneDec(), // %0 apr + LiquidationPenalty: d("0.05"), + AuctionSize: i(10000000000), + Prefix: 0x23, + SpotMarketID: "busd:usd", + LiquidationMarketID: "busd:usd", + KeeperRewardPercentage: d("0.01"), + CheckCollateralizationIndexCount: i(10), + ConversionFactor: i(8), }, }, DebtParam: cdp.DebtParam{ @@ -165,14 +197,24 @@ func NewCDPGenStateMulti() app.GenesisState { ReferenceAsset: "usd", ConversionFactor: i(6), DebtFloor: i(10000000), - SavingsRate: d("0.95"), }, }, - StartingCdpID: cdp.DefaultCdpStartingID, - DebtDenom: cdp.DefaultDebtDenom, - GovDenom: cdp.DefaultGovDenom, - CDPs: cdp.CDPs{}, - PreviousDistributionTime: cdp.DefaultPreviousDistributionTime, + StartingCdpID: cdp.DefaultCdpStartingID, + DebtDenom: cdp.DefaultDebtDenom, + GovDenom: cdp.DefaultGovDenom, + CDPs: cdp.CDPs{}, + PreviousAccumulationTimes: cdp.GenesisAccumulationTimes{ + cdp.NewGenesisAccumulationTime("btc-a", time.Time{}, sdk.OneDec()), + cdp.NewGenesisAccumulationTime("xrp-a", time.Time{}, sdk.OneDec()), + cdp.NewGenesisAccumulationTime("busd-a", time.Time{}, sdk.OneDec()), + cdp.NewGenesisAccumulationTime("bnb-a", time.Time{}, sdk.OneDec()), + }, + TotalPrincipals: cdp.GenesisTotalPrincipals{ + cdp.NewGenesisTotalPrincipal("btc-a", sdk.ZeroInt()), + cdp.NewGenesisTotalPrincipal("xrp-a", sdk.ZeroInt()), + cdp.NewGenesisTotalPrincipal("busd-a", sdk.ZeroInt()), + cdp.NewGenesisTotalPrincipal("bnb-a", sdk.ZeroInt()), + }, } return app.GenesisState{cdp.ModuleName: cdp.ModuleCdc.MustMarshalJSON(cdpGenesis)} } @@ -180,38 +222,41 @@ func NewCDPGenStateMulti() app.GenesisState { func NewCDPGenStateHighDebtLimit() app.GenesisState { cdpGenesis := cdp.GenesisState{ Params: cdp.Params{ - GlobalDebtLimit: sdk.NewInt64Coin("usdx", 100000000000000), - SurplusAuctionThreshold: cdp.DefaultSurplusThreshold, - SurplusAuctionLot: cdp.DefaultSurplusLot, - DebtAuctionThreshold: cdp.DefaultDebtThreshold, - DebtAuctionLot: cdp.DefaultDebtLot, - SavingsDistributionFrequency: cdp.DefaultSavingsDistributionFrequency, + GlobalDebtLimit: sdk.NewInt64Coin("usdx", 100000000000000), + SurplusAuctionThreshold: cdp.DefaultSurplusThreshold, + SurplusAuctionLot: cdp.DefaultSurplusLot, + DebtAuctionThreshold: cdp.DefaultDebtThreshold, + DebtAuctionLot: cdp.DefaultDebtLot, CollateralParams: cdp.CollateralParams{ { - Denom: "xrp", - Type: "xrp-a", - LiquidationRatio: sdk.MustNewDecFromStr("2.0"), - DebtLimit: sdk.NewInt64Coin("usdx", 50000000000000), - StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), // %5 apr - LiquidationPenalty: d("0.05"), - AuctionSize: i(7000000000), - Prefix: 0x20, - SpotMarketID: "xrp:usd", - LiquidationMarketID: "xrp:usd", - ConversionFactor: i(6), + Denom: "xrp", + Type: "xrp-a", + LiquidationRatio: sdk.MustNewDecFromStr("2.0"), + DebtLimit: sdk.NewInt64Coin("usdx", 50000000000000), + StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), // %5 apr + LiquidationPenalty: d("0.05"), + AuctionSize: i(7000000000), + Prefix: 0x20, + SpotMarketID: "xrp:usd", + LiquidationMarketID: "xrp:usd", + KeeperRewardPercentage: d("0.01"), + CheckCollateralizationIndexCount: i(10), + ConversionFactor: i(6), }, { - Denom: "btc", - Type: "btc-a", - LiquidationRatio: sdk.MustNewDecFromStr("1.5"), - DebtLimit: sdk.NewInt64Coin("usdx", 50000000000000), - StabilityFee: sdk.MustNewDecFromStr("1.000000000782997609"), // %2.5 apr - LiquidationPenalty: d("0.025"), - AuctionSize: i(10000000), - Prefix: 0x21, - SpotMarketID: "btc:usd", - LiquidationMarketID: "btc:usd", - ConversionFactor: i(8), + Denom: "btc", + Type: "btc-a", + LiquidationRatio: sdk.MustNewDecFromStr("1.5"), + DebtLimit: sdk.NewInt64Coin("usdx", 50000000000000), + StabilityFee: sdk.MustNewDecFromStr("1.000000000782997609"), // %2.5 apr + LiquidationPenalty: d("0.025"), + AuctionSize: i(10000000), + Prefix: 0x21, + SpotMarketID: "btc:usd", + LiquidationMarketID: "btc:usd", + KeeperRewardPercentage: d("0.01"), + CheckCollateralizationIndexCount: i(10), + ConversionFactor: i(8), }, }, DebtParam: cdp.DebtParam{ @@ -219,24 +264,30 @@ func NewCDPGenStateHighDebtLimit() app.GenesisState { ReferenceAsset: "usd", ConversionFactor: i(6), DebtFloor: i(10000000), - SavingsRate: d("0.95"), }, }, - StartingCdpID: cdp.DefaultCdpStartingID, - DebtDenom: cdp.DefaultDebtDenom, - GovDenom: cdp.DefaultGovDenom, - CDPs: cdp.CDPs{}, - PreviousDistributionTime: cdp.DefaultPreviousDistributionTime, + StartingCdpID: cdp.DefaultCdpStartingID, + DebtDenom: cdp.DefaultDebtDenom, + GovDenom: cdp.DefaultGovDenom, + CDPs: cdp.CDPs{}, + PreviousAccumulationTimes: cdp.GenesisAccumulationTimes{ + cdp.NewGenesisAccumulationTime("btc-a", time.Time{}, sdk.OneDec()), + cdp.NewGenesisAccumulationTime("xrp-a", time.Time{}, sdk.OneDec()), + }, + TotalPrincipals: cdp.GenesisTotalPrincipals{ + cdp.NewGenesisTotalPrincipal("btc-a", sdk.ZeroInt()), + cdp.NewGenesisTotalPrincipal("xrp-a", sdk.ZeroInt()), + }, } return app.GenesisState{cdp.ModuleName: cdp.ModuleCdc.MustMarshalJSON(cdpGenesis)} } func cdps() (cdps cdp.CDPs) { _, addrs := app.GeneratePrivKeyAddressPairs(3) - c1 := cdp.NewCDP(uint64(1), addrs[0], sdk.NewCoin("xrp", sdk.NewInt(10000000)), "xrp-a", sdk.NewCoin("usdx", sdk.NewInt(8000000)), tmtime.Canonical(time.Now())) - c2 := cdp.NewCDP(uint64(2), addrs[1], sdk.NewCoin("xrp", sdk.NewInt(100000000)), "xrp-a", sdk.NewCoin("usdx", sdk.NewInt(10000000)), tmtime.Canonical(time.Now())) - c3 := cdp.NewCDP(uint64(3), addrs[1], sdk.NewCoin("btc", sdk.NewInt(1000000000)), "btc-a", sdk.NewCoin("usdx", sdk.NewInt(10000000)), tmtime.Canonical(time.Now())) - c4 := cdp.NewCDP(uint64(4), addrs[2], sdk.NewCoin("xrp", sdk.NewInt(1000000000)), "xrp-a", sdk.NewCoin("usdx", sdk.NewInt(500000000)), tmtime.Canonical(time.Now())) + c1 := cdp.NewCDP(uint64(1), addrs[0], sdk.NewCoin("xrp", sdk.NewInt(10000000)), "xrp-a", sdk.NewCoin("usdx", sdk.NewInt(8000000)), tmtime.Canonical(time.Now()), sdk.OneDec()) + c2 := cdp.NewCDP(uint64(2), addrs[1], sdk.NewCoin("xrp", sdk.NewInt(100000000)), "xrp-a", sdk.NewCoin("usdx", sdk.NewInt(10000000)), tmtime.Canonical(time.Now()), sdk.OneDec()) + c3 := cdp.NewCDP(uint64(3), addrs[1], sdk.NewCoin("btc", sdk.NewInt(1000000000)), "btc-a", sdk.NewCoin("usdx", sdk.NewInt(10000000)), tmtime.Canonical(time.Now()), sdk.OneDec()) + c4 := cdp.NewCDP(uint64(4), addrs[2], sdk.NewCoin("xrp", sdk.NewInt(1000000000)), "xrp-a", sdk.NewCoin("usdx", sdk.NewInt(500000000)), tmtime.Canonical(time.Now()), sdk.OneDec()) cdps = append(cdps, c1, c2, c3, c4) return } diff --git a/x/cdp/keeper/interest.go b/x/cdp/keeper/interest.go new file mode 100644 index 00000000..e841653c --- /dev/null +++ b/x/cdp/keeper/interest.go @@ -0,0 +1,164 @@ +package keeper + +import ( + "fmt" + "math" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/kava-labs/kava/x/cdp/types" +) + +var ( + scalingFactor = 1e18 + secondsPerYear = 31536000 +) + +// AccumulateInterest calculates the new interest that has accrued for the input collateral type based on the total amount of principal +// that has been created with that collateral type and the amount of time that has passed since interest was last accumulated +func (k Keeper) AccumulateInterest(ctx sdk.Context, ctype string) error { + previousAccrualTime, found := k.GetPreviousAccrualTime(ctx, ctype) + if !found { + k.SetPreviousAccrualTime(ctx, ctype, ctx.BlockTime()) + return nil + } + + timeElapsed := int64(math.RoundToEven( + ctx.BlockTime().Sub(previousAccrualTime).Seconds(), + )) + if timeElapsed == 0 { + return nil + } + + totalPrincipalPrior := k.GetTotalPrincipal(ctx, ctype, types.DefaultStableDenom) + if totalPrincipalPrior.IsZero() || totalPrincipalPrior.IsNegative() { + k.SetPreviousAccrualTime(ctx, ctype, ctx.BlockTime()) + return nil + } + + interestFactorPrior, foundInterestFactorPrior := k.GetInterestFactor(ctx, ctype) + if !foundInterestFactorPrior { + k.SetInterestFactor(ctx, ctype, sdk.OneDec()) + // set previous accrual time exit early because interest accumulated will be zero + k.SetPreviousAccrualTime(ctx, ctype, ctx.BlockTime()) + return nil + } + + borrowRateSpy := k.getFeeRate(ctx, ctype) + if borrowRateSpy.Equal(sdk.OneDec()) { + k.SetPreviousAccrualTime(ctx, ctype, ctx.BlockTime()) + return nil + } + interestFactor := CalculateInterestFactor(borrowRateSpy, sdk.NewInt(timeElapsed)) + interestAccumulated := (interestFactor.Mul(totalPrincipalPrior.ToDec())).RoundInt().Sub(totalPrincipalPrior) + if interestAccumulated.IsZero() { + // in the case accumulated interest rounds to zero, exit early without updating accrual time + return nil + } + err := k.MintDebtCoins(ctx, types.ModuleName, k.GetDebtDenom(ctx), sdk.NewCoin(types.DefaultStableDenom, interestAccumulated)) + if err != nil { + return err + } + + dp, found := k.GetDebtParam(ctx, types.DefaultStableDenom) + if !found { + panic(fmt.Sprintf("Debt parameters for %s not found", types.DefaultStableDenom)) + } + + newFeesSurplus := interestAccumulated + + // mint surplus coins to the liquidator module account. + if newFeesSurplus.IsPositive() { + err := k.supplyKeeper.MintCoins(ctx, types.LiquidatorMacc, sdk.NewCoins(sdk.NewCoin(dp.Denom, newFeesSurplus))) + if err != nil { + return err + } + } + + interestFactorNew := interestFactorPrior.Mul(interestFactor) + totalPrincipalNew := totalPrincipalPrior.Add(interestAccumulated) + + k.SetTotalPrincipal(ctx, ctype, types.DefaultStableDenom, totalPrincipalNew) + k.SetInterestFactor(ctx, ctype, interestFactorNew) + k.SetPreviousAccrualTime(ctx, ctype, ctx.BlockTime()) + + return nil +} + +// CalculateInterestFactor calculates the simple interest scaling factor, +// which is equal to: (per-second interest rate ** number of seconds elapsed) +// Will return 1.000x, multiply by principal to get new principal with added interest +func CalculateInterestFactor(perSecondInterestRate sdk.Dec, secondsElapsed sdk.Int) sdk.Dec { + scalingFactorUint := sdk.NewUint(uint64(scalingFactor)) + scalingFactorInt := sdk.NewInt(int64(scalingFactor)) + + // Convert per-second interest rate to a uint scaled by 1e18 + interestMantissa := sdk.NewUint(perSecondInterestRate.MulInt(scalingFactorInt).RoundInt().Uint64()) + // Convert seconds elapsed to uint (*not scaled*) + secondsElapsedUint := sdk.NewUint(secondsElapsed.Uint64()) + // Calculate the interest factor as a uint scaled by 1e18 + interestFactorMantissa := sdk.RelativePow(interestMantissa, secondsElapsedUint, scalingFactorUint) + + // Convert interest factor to an unscaled sdk.Dec + return sdk.NewDecFromBigInt(interestFactorMantissa.BigInt()).QuoInt(scalingFactorInt) +} + +// SynchronizeInterest updates the input cdp object to reflect the current accumulated interest, updates the cdp state in the store, +// and returns the updated cdp object +func (k Keeper) SynchronizeInterest(ctx sdk.Context, cdp types.CDP) types.CDP { + globalInterestFactor, found := k.GetInterestFactor(ctx, cdp.Type) + if !found { + k.SetInterestFactor(ctx, cdp.Type, sdk.OneDec()) + cdp.InterestFactor = sdk.OneDec() + cdp.FeesUpdated = ctx.BlockTime() + k.SetCDP(ctx, cdp) + return cdp + } + + accumulatedInterest := k.CalculateNewInterest(ctx, cdp) + if accumulatedInterest.IsZero() { + // accumulated interest is zero if apy is zero or are if the total fees for all cdps round to zero + + prevAccrualTime, found := k.GetPreviousAccrualTime(ctx, cdp.Type) + if !found { + return cdp + } + if cdp.FeesUpdated.Equal(prevAccrualTime) { + // if all fees are rounding to zero, don't update FeesUpdated + return cdp + } + // if apy is zero, we need to update FeesUpdated + cdp.FeesUpdated = ctx.BlockTime() + k.SetCDP(ctx, cdp) + } + + cdp.AccumulatedFees = cdp.AccumulatedFees.Add(accumulatedInterest) + cdp.FeesUpdated = ctx.BlockTime() + cdp.InterestFactor = globalInterestFactor + collateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Type, cdp.GetTotalPrincipal()) + k.UpdateCdpAndCollateralRatioIndex(ctx, cdp, collateralToDebtRatio) + return cdp +} + +// CalculateNewInterest returns the amount of interest that has accrued to the cdp since its interest was last synchronized +func (k Keeper) CalculateNewInterest(ctx sdk.Context, cdp types.CDP) sdk.Coin { + globalInterestFactor, found := k.GetInterestFactor(ctx, cdp.Type) + if !found { + return sdk.NewCoin(cdp.AccumulatedFees.Denom, sdk.ZeroInt()) + } + cdpInterestFactor := globalInterestFactor.Quo(cdp.InterestFactor) + if cdpInterestFactor.Equal(sdk.OneDec()) { + return sdk.NewCoin(cdp.AccumulatedFees.Denom, sdk.ZeroInt()) + } + accumulatedInterest := cdp.GetTotalPrincipal().Amount.ToDec().Mul(cdpInterestFactor).RoundInt().Sub(cdp.GetTotalPrincipal().Amount) + return sdk.NewCoin(cdp.AccumulatedFees.Denom, accumulatedInterest) +} + +// SynchronizeInterestForRiskyCDPs synchronizes the interest for the slice of cdps with the lowest collateral:debt ratio +func (k Keeper) SynchronizeInterestForRiskyCDPs(ctx sdk.Context, slice sdk.Int, targetRatio sdk.Dec, collateralType string) error { + cdps := k.GetSliceOfCDPsByRatioAndType(ctx, slice, targetRatio, collateralType) + for _, cdp := range cdps { + k.SynchronizeInterest(ctx, cdp) + } + return nil +} diff --git a/x/cdp/keeper/interest_test.go b/x/cdp/keeper/interest_test.go new file mode 100644 index 00000000..c8db0346 --- /dev/null +++ b/x/cdp/keeper/interest_test.go @@ -0,0 +1,763 @@ +package keeper_test + +import ( + "testing" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/stretchr/testify/suite" + + abci "github.com/tendermint/tendermint/abci/types" + tmtime "github.com/tendermint/tendermint/types/time" + + "github.com/kava-labs/kava/app" + "github.com/kava-labs/kava/x/cdp/keeper" + "github.com/kava-labs/kava/x/cdp/types" +) + +type InterestTestSuite struct { + suite.Suite + + keeper keeper.Keeper + app app.TestApp + ctx sdk.Context +} + +func (suite *InterestTestSuite) SetupTest() { + tApp := app.NewTestApp() + ctx := tApp.NewContext(true, abci.Header{Height: 1, Time: tmtime.Now()}) + tApp.InitializeFromGenesisStates( + NewPricefeedGenStateMulti(), + NewCDPGenStateMulti(), + ) + keeper := tApp.GetCDPKeeper() + suite.app = tApp + suite.ctx = ctx + suite.keeper = keeper +} + +// createCdps is a helper function to create two CDPs each with zero fees +func (suite *InterestTestSuite) createCdps() { + // create 2 accounts in the state and give them some coins + // create two private key pair addresses + _, addrs := app.GeneratePrivKeyAddressPairs(2) + ak := suite.app.GetAccountKeeper() + // setup the first account + acc := ak.NewAccountWithAddress(suite.ctx, addrs[0]) + acc.SetCoins(cs(c("xrp", 200000000), c("btc", 500000000))) + + ak.SetAccount(suite.ctx, acc) + // now setup the second account + acc2 := ak.NewAccountWithAddress(suite.ctx, addrs[1]) + acc2.SetCoins(cs(c("xrp", 200000000), c("btc", 500000000))) + ak.SetAccount(suite.ctx, acc2) + + // now create two cdps with the addresses we just created + // use the created account to create a cdp that SHOULD have fees updated + // to get a ratio between 100 - 110% of liquidation ratio we can use 200xrp ($50) and 24 usdx (208% collateralization with liquidation ratio of 200%) + // create CDP for the first address + err := suite.keeper.AddCdp(suite.ctx, addrs[0], c("xrp", 200000000), c("usdx", 24000000), "xrp-a") + suite.NoError(err) // check that no error was thrown + + // use the other account to create a cdp that SHOULD NOT have fees updated - 500% collateralization + // create CDP for the second address + err = suite.keeper.AddCdp(suite.ctx, addrs[1], c("xrp", 200000000), c("usdx", 10000000), "xrp-a") + suite.NoError(err) // check that no error was thrown + +} + +func (suite *InterestTestSuite) TestCalculateInterestFactor() { + type args struct { + perSecondInterestRate sdk.Dec + timeElapsed sdk.Int + expectedValue sdk.Dec + } + + type test struct { + name string + args args + } + + oneYearInSeconds := int64(31536000) + + testCases := []test{ + { + "1 year", + args{ + perSecondInterestRate: sdk.MustNewDecFromStr("1.000000005555"), + timeElapsed: sdk.NewInt(oneYearInSeconds), + expectedValue: sdk.MustNewDecFromStr("1.191463614477847370"), + }, + }, + { + "10 year", + args{ + perSecondInterestRate: sdk.MustNewDecFromStr("1.000000005555"), + timeElapsed: sdk.NewInt(oneYearInSeconds * 10), + expectedValue: sdk.MustNewDecFromStr("5.765113233897391189"), + }, + }, + { + "1 month", + args{ + perSecondInterestRate: sdk.MustNewDecFromStr("1.000000005555"), + timeElapsed: sdk.NewInt(oneYearInSeconds / 12), + expectedValue: sdk.MustNewDecFromStr("1.014705619075717373"), + }, + }, + { + "1 day", + args{ + perSecondInterestRate: sdk.MustNewDecFromStr("1.000000005555"), + timeElapsed: sdk.NewInt(oneYearInSeconds / 365), + expectedValue: sdk.MustNewDecFromStr("1.000480067194057924"), + }, + }, + { + "1 year: low interest rate", + args{ + perSecondInterestRate: sdk.MustNewDecFromStr("1.000000000555"), + timeElapsed: sdk.NewInt(oneYearInSeconds), + expectedValue: sdk.MustNewDecFromStr("1.017656545925063632"), + }, + }, + { + "1 year, lower interest rate", + args{ + perSecondInterestRate: sdk.MustNewDecFromStr("1.000000000055"), + timeElapsed: sdk.NewInt(oneYearInSeconds), + expectedValue: sdk.MustNewDecFromStr("1.001735985079841390"), + }, + }, + { + "1 year, lowest interest rate", + args{ + perSecondInterestRate: sdk.MustNewDecFromStr("1.000000000005"), + timeElapsed: sdk.NewInt(oneYearInSeconds), + expectedValue: sdk.MustNewDecFromStr("1.000157692432076670"), + }, + }, + { + "1 year: high interest rate", + args{ + perSecondInterestRate: sdk.MustNewDecFromStr("1.000000055555"), + timeElapsed: sdk.NewInt(oneYearInSeconds), + expectedValue: sdk.MustNewDecFromStr("5.766022095987868825"), + }, + }, + { + "1 year: higher interest rate", + args{ + perSecondInterestRate: sdk.MustNewDecFromStr("1.000000555555"), + timeElapsed: sdk.NewInt(oneYearInSeconds), + expectedValue: sdk.MustNewDecFromStr("40628388.864535408465693310"), + }, + }, + // If we raise the per second interest rate too much we'll cause an integer overflow. + // For example, perSecondInterestRate: '1.000005555555' will cause a panic. + { + "1 year: highest interest rate", + args{ + perSecondInterestRate: sdk.MustNewDecFromStr("1.000001555555"), + timeElapsed: sdk.NewInt(oneYearInSeconds), + expectedValue: sdk.MustNewDecFromStr("2017093013158200407564.613502861572552603"), + }, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + interestFactor := keeper.CalculateInterestFactor(tc.args.perSecondInterestRate, tc.args.timeElapsed) + suite.Require().Equal(tc.args.expectedValue, interestFactor) + }) + } +} + +func (suite *InterestTestSuite) TestAccumulateInterest() { + + type args struct { + ctype string + initialTime time.Time + totalPrincipal sdk.Int + timeElapsed int + expectedTotalPrincipal sdk.Int + expectedLastAccrualTime time.Time + } + + type test struct { + name string + args args + } + oneYearInSeconds := 31536000 + + testCases := []test{ + { + "1 year", + args{ + ctype: "bnb-a", + initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + totalPrincipal: sdk.NewInt(100000000000000), + timeElapsed: oneYearInSeconds, + expectedTotalPrincipal: sdk.NewInt(105000000000012), + expectedLastAccrualTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC).Add(time.Duration(int(time.Second) * oneYearInSeconds)), + }, + }, + { + "1 year - zero principal", + args{ + ctype: "bnb-a", + initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + totalPrincipal: sdk.ZeroInt(), + timeElapsed: oneYearInSeconds, + expectedTotalPrincipal: sdk.ZeroInt(), + expectedLastAccrualTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC).Add(time.Duration(int(time.Second) * oneYearInSeconds)), + }, + }, + { + "1 month", + args{ + ctype: "bnb-a", + initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + totalPrincipal: sdk.NewInt(100000000000000), + timeElapsed: 86400 * 30, + expectedTotalPrincipal: sdk.NewInt(100401820189198), + expectedLastAccrualTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC).Add(time.Duration(int(time.Second) * 86400 * 30)), + }, + }, + { + "1 month - interest rounds to zero", + args{ + ctype: "bnb-a", + initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + totalPrincipal: sdk.NewInt(10), + timeElapsed: 86400 * 30, + expectedTotalPrincipal: sdk.NewInt(10), + expectedLastAccrualTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + }, + }, + { + "7 seconds", + args{ + ctype: "bnb-a", + initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + totalPrincipal: sdk.NewInt(100000000000000), + timeElapsed: 7, + expectedTotalPrincipal: sdk.NewInt(100000001082988), + expectedLastAccrualTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC).Add(time.Duration(int(time.Second) * 7)), + }, + }, + { + "7 seconds - interest rounds to zero", + args{ + ctype: "bnb-a", + initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + totalPrincipal: sdk.NewInt(30000000), + timeElapsed: 7, + expectedTotalPrincipal: sdk.NewInt(30000000), + expectedLastAccrualTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + }, + }, + { + "7 seconds - zero interest", + args{ + ctype: "busd-a", + initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + totalPrincipal: sdk.NewInt(100000000000000), + timeElapsed: 7, + expectedTotalPrincipal: sdk.NewInt(100000000000000), + expectedLastAccrualTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC).Add(time.Duration(int(time.Second) * 7)), + }, + }, + } + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime) + suite.keeper.SetTotalPrincipal(suite.ctx, tc.args.ctype, types.DefaultStableDenom, tc.args.totalPrincipal) + suite.keeper.SetPreviousAccrualTime(suite.ctx, tc.args.ctype, suite.ctx.BlockTime()) + suite.keeper.SetInterestFactor(suite.ctx, tc.args.ctype, sdk.OneDec()) + + updatedBlockTime := suite.ctx.BlockTime().Add(time.Duration(int(time.Second) * tc.args.timeElapsed)) + suite.ctx = suite.ctx.WithBlockTime(updatedBlockTime) + err := suite.keeper.AccumulateInterest(suite.ctx, tc.args.ctype) + suite.Require().NoError(err) + + actualTotalPrincipal := suite.keeper.GetTotalPrincipal(suite.ctx, tc.args.ctype, types.DefaultStableDenom) + suite.Require().Equal(tc.args.expectedTotalPrincipal, actualTotalPrincipal) + actualAccrualTime, _ := suite.keeper.GetPreviousAccrualTime(suite.ctx, tc.args.ctype) + suite.Require().Equal(tc.args.expectedLastAccrualTime, actualAccrualTime) + }) + } +} + +// TestSynchronizeInterest tests the functionality of synchronizing the accumulated interest for CDPs +func (suite *InterestTestSuite) TestSynchronizeInterest() { + type args struct { + ctype string + initialTime time.Time + initialCollateral sdk.Coin + initialPrincipal sdk.Coin + timeElapsed int + expectedFees sdk.Coin + expectedFeesUpdatedTime time.Time + } + + type test struct { + name string + args args + } + + oneYearInSeconds := 31536000 + testCases := []test{ + { + "1 year", + args{ + ctype: "bnb-a", + initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + initialCollateral: c("bnb", 1000000000000), + initialPrincipal: c("usdx", 100000000000), + timeElapsed: oneYearInSeconds, + expectedFees: c("usdx", 5000000000), + expectedFeesUpdatedTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC).Add(time.Duration(int(time.Second) * oneYearInSeconds)), + }, + }, + { + "1 month", + args{ + ctype: "bnb-a", + initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + initialCollateral: c("bnb", 1000000000000), + initialPrincipal: c("usdx", 100000000000), + timeElapsed: 86400 * 30, + expectedFees: c("usdx", 401820189), + expectedFeesUpdatedTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC).Add(time.Duration(int(time.Second) * 86400 * 30)), + }, + }, + { + "7 seconds", + args{ + ctype: "bnb-a", + initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + initialCollateral: c("bnb", 1000000000000), + initialPrincipal: c("usdx", 100000000000), + timeElapsed: 7, + expectedFees: c("usdx", 1083), + expectedFeesUpdatedTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC).Add(time.Duration(int(time.Second) * 7)), + }, + }, + { + "7 seconds - zero apy", + args{ + ctype: "busd-a", + initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + initialCollateral: c("busd", 10000000000000), + initialPrincipal: c("usdx", 10000000000), + timeElapsed: 7, + expectedFees: c("usdx", 0), + expectedFeesUpdatedTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC).Add(time.Duration(int(time.Second) * 7)), + }, + }, + { + "7 seconds - fees round to zero", + args{ + ctype: "bnb-a", + initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + initialCollateral: c("bnb", 1000000000), + initialPrincipal: c("usdx", 10000000), + timeElapsed: 7, + expectedFees: c("usdx", 0), + expectedFeesUpdatedTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + }, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() + suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime) + + // setup account state + _, addrs := app.GeneratePrivKeyAddressPairs(1) + ak := suite.app.GetAccountKeeper() + // setup the first account + acc := ak.NewAccountWithAddress(suite.ctx, addrs[0]) + ak.SetAccount(suite.ctx, acc) + sk := suite.app.GetSupplyKeeper() + err := sk.MintCoins(suite.ctx, types.ModuleName, cs(tc.args.initialCollateral)) + suite.Require().NoError(err) + err = sk.SendCoinsFromModuleToAccount(suite.ctx, types.ModuleName, addrs[0], cs(tc.args.initialCollateral)) + suite.Require().NoError(err) + + // setup pricefeed + pk := suite.app.GetPriceFeedKeeper() + pk.SetPrice(suite.ctx, sdk.AccAddress{}, "bnb:usd", d("17.25"), tc.args.expectedFeesUpdatedTime.Add(time.Second)) + pk.SetPrice(suite.ctx, sdk.AccAddress{}, "busd:usd", d("1"), tc.args.expectedFeesUpdatedTime.Add(time.Second)) + + // setup cdp state + suite.keeper.SetPreviousAccrualTime(suite.ctx, tc.args.ctype, suite.ctx.BlockTime()) + suite.keeper.SetInterestFactor(suite.ctx, tc.args.ctype, sdk.OneDec()) + err = suite.keeper.AddCdp(suite.ctx, addrs[0], tc.args.initialCollateral, tc.args.initialPrincipal, tc.args.ctype) + suite.Require().NoError(err) + + updatedBlockTime := suite.ctx.BlockTime().Add(time.Duration(int(time.Second) * tc.args.timeElapsed)) + suite.ctx = suite.ctx.WithBlockTime(updatedBlockTime) + err = suite.keeper.AccumulateInterest(suite.ctx, tc.args.ctype) + suite.Require().NoError(err) + + cdp, found := suite.keeper.GetCDP(suite.ctx, tc.args.ctype, 1) + suite.Require().True(found) + + cdp = suite.keeper.SynchronizeInterest(suite.ctx, cdp) + + suite.Require().Equal(tc.args.expectedFees, cdp.AccumulatedFees) + suite.Require().Equal(tc.args.expectedFeesUpdatedTime, cdp.FeesUpdated) + + }) + } +} + +func (suite *InterestTestSuite) TestMultipleCDPInterest() { + type args struct { + ctype string + initialTime time.Time + blockInterval int + numberOfBlocks int + initialCDPCollateral sdk.Coin + initialCDPPrincipal sdk.Coin + numberOfCdps int + expectedFeesPerCDP sdk.Coin + expectedTotalPrincipalPerCDP sdk.Coin + expectedFeesUpdatedTime time.Time + expectedTotalPrincipal sdk.Int + expectedDebtBalance sdk.Int + expectedStableBalance sdk.Int + expectedSumOfCDPPrincipal sdk.Int + } + + type test struct { + name string + args args + } + + testCases := []test{ + { + "1 block", + args{ + ctype: "bnb-a", + initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + blockInterval: 7, + numberOfBlocks: 1, + initialCDPCollateral: c("bnb", 10000000000), + initialCDPPrincipal: c("usdx", 500000000), + numberOfCdps: 100, + expectedFeesPerCDP: c("usdx", 5), + expectedTotalPrincipalPerCDP: c("usdx", 500000005), + expectedFeesUpdatedTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC).Add(time.Duration(int(time.Second) * 7)), + expectedTotalPrincipal: i(50000000541), + expectedDebtBalance: i(50000000541), + expectedStableBalance: i(50000000541), + expectedSumOfCDPPrincipal: i(50000000500), + }, + }, + { + "100 blocks", + args{ + ctype: "bnb-a", + initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + blockInterval: 7, + numberOfBlocks: 100, + initialCDPCollateral: c("bnb", 10000000000), + initialCDPPrincipal: c("usdx", 500000000), + numberOfCdps: 100, + expectedFeesPerCDP: c("usdx", 541), + expectedTotalPrincipalPerCDP: c("usdx", 500000541), + expectedFeesUpdatedTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC).Add(time.Duration(int(time.Second) * 7 * 100)), + expectedTotalPrincipal: i(50000054100), + expectedDebtBalance: i(50000054100), + expectedStableBalance: i(50000054100), + expectedSumOfCDPPrincipal: i(50000054100), + }, + }, + { + "10000 blocks", + args{ + ctype: "bnb-a", + initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + blockInterval: 7, + numberOfBlocks: 10000, + initialCDPCollateral: c("bnb", 10000000000), + initialCDPPrincipal: c("usdx", 500000000), + numberOfCdps: 100, + expectedFeesPerCDP: c("usdx", 54152), + expectedTotalPrincipalPerCDP: c("usdx", 500054152), + expectedFeesUpdatedTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC).Add(time.Duration(int(time.Second) * 7 * 10000)), + expectedTotalPrincipal: i(50005418990), + expectedDebtBalance: i(50005418990), + expectedStableBalance: i(50005418990), + expectedSumOfCDPPrincipal: i(50005415200), + }, + }, + } + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() + suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime) + + // setup pricefeed + pk := suite.app.GetPriceFeedKeeper() + pk.SetPrice(suite.ctx, sdk.AccAddress{}, "bnb:usd", d("17.25"), tc.args.expectedFeesUpdatedTime.Add(time.Second)) + + // setup cdp state + suite.keeper.SetPreviousAccrualTime(suite.ctx, tc.args.ctype, suite.ctx.BlockTime()) + suite.keeper.SetInterestFactor(suite.ctx, tc.args.ctype, sdk.OneDec()) + + // setup account state + _, addrs := app.GeneratePrivKeyAddressPairs(tc.args.numberOfCdps) + for j := 0; j < tc.args.numberOfCdps; j++ { + ak := suite.app.GetAccountKeeper() + // setup the first account + acc := ak.NewAccountWithAddress(suite.ctx, addrs[j]) + ak.SetAccount(suite.ctx, acc) + sk := suite.app.GetSupplyKeeper() + err := sk.MintCoins(suite.ctx, types.ModuleName, cs(tc.args.initialCDPCollateral)) + suite.Require().NoError(err) + err = sk.SendCoinsFromModuleToAccount(suite.ctx, types.ModuleName, addrs[j], cs(tc.args.initialCDPCollateral)) + suite.Require().NoError(err) + err = suite.keeper.AddCdp(suite.ctx, addrs[j], tc.args.initialCDPCollateral, tc.args.initialCDPPrincipal, tc.args.ctype) + suite.Require().NoError(err) + } + + // run a number of blocks where CDPs are not synchronized + for j := 0; j < tc.args.numberOfBlocks; j++ { + updatedBlockTime := suite.ctx.BlockTime().Add(time.Duration(int(time.Second) * tc.args.blockInterval)) + suite.ctx = suite.ctx.WithBlockTime(updatedBlockTime) + err := suite.keeper.AccumulateInterest(suite.ctx, tc.args.ctype) + suite.Require().NoError(err) + } + + sk := suite.app.GetSupplyKeeper() + supplyTotal := sk.GetSupply(suite.ctx).GetTotal() + debtSupply := supplyTotal.AmountOf(types.DefaultDebtDenom) + usdxSupply := supplyTotal.AmountOf(types.DefaultStableDenom) + totalPrincipal := suite.keeper.GetTotalPrincipal(suite.ctx, tc.args.ctype, types.DefaultStableDenom) + + suite.Require().Equal(tc.args.expectedDebtBalance, debtSupply) + suite.Require().Equal(tc.args.expectedStableBalance, usdxSupply) + suite.Require().Equal(tc.args.expectedTotalPrincipal, totalPrincipal) + + sumOfCDPPrincipal := sdk.ZeroInt() + + for j := 0; j < tc.args.numberOfCdps; j++ { + cdp, found := suite.keeper.GetCDP(suite.ctx, tc.args.ctype, uint64(j+1)) + suite.Require().True(found) + cdp = suite.keeper.SynchronizeInterest(suite.ctx, cdp) + suite.Require().Equal(tc.args.expectedFeesPerCDP, cdp.AccumulatedFees) + suite.Require().Equal(tc.args.expectedTotalPrincipalPerCDP, cdp.GetTotalPrincipal()) + suite.Require().Equal(tc.args.expectedFeesUpdatedTime, cdp.FeesUpdated) + sumOfCDPPrincipal = sumOfCDPPrincipal.Add(cdp.GetTotalPrincipal().Amount) + } + + suite.Require().Equal(tc.args.expectedSumOfCDPPrincipal, sumOfCDPPrincipal) + + }) + } +} + +// TestSynchronizeInterest tests the functionality of synchronizing the accumulated interest for CDPs +func (suite *InterestTestSuite) TestCalculateCDPInterest() { + type args struct { + ctype string + initialTime time.Time + initialCollateral sdk.Coin + initialPrincipal sdk.Coin + timeElapsed int + expectedFees sdk.Coin + } + + type test struct { + name string + args args + } + + oneYearInSeconds := 31536000 + testCases := []test{ + { + "1 year", + args{ + ctype: "bnb-a", + initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + initialCollateral: c("bnb", 1000000000000), + initialPrincipal: c("usdx", 100000000000), + timeElapsed: oneYearInSeconds, + expectedFees: c("usdx", 5000000000), + }, + }, + { + "1 month", + args{ + ctype: "bnb-a", + initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + initialCollateral: c("bnb", 1000000000000), + initialPrincipal: c("usdx", 100000000000), + timeElapsed: 86400 * 30, + expectedFees: c("usdx", 401820189), + }, + }, + { + "7 seconds", + args{ + ctype: "bnb-a", + initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + initialCollateral: c("bnb", 1000000000000), + initialPrincipal: c("usdx", 100000000000), + timeElapsed: 7, + expectedFees: c("usdx", 1083), + }, + }, + { + "7 seconds - fees round to zero", + args{ + ctype: "bnb-a", + initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + initialCollateral: c("bnb", 1000000000), + initialPrincipal: c("usdx", 10000000), + timeElapsed: 7, + expectedFees: c("usdx", 0), + }, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() + suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime) + + // setup account state + _, addrs := app.GeneratePrivKeyAddressPairs(1) + ak := suite.app.GetAccountKeeper() + // setup the first account + acc := ak.NewAccountWithAddress(suite.ctx, addrs[0]) + ak.SetAccount(suite.ctx, acc) + sk := suite.app.GetSupplyKeeper() + err := sk.MintCoins(suite.ctx, types.ModuleName, cs(tc.args.initialCollateral)) + suite.Require().NoError(err) + err = sk.SendCoinsFromModuleToAccount(suite.ctx, types.ModuleName, addrs[0], cs(tc.args.initialCollateral)) + suite.Require().NoError(err) + + // setup pricefeed + pk := suite.app.GetPriceFeedKeeper() + pk.SetPrice(suite.ctx, sdk.AccAddress{}, "bnb:usd", d("17.25"), tc.args.initialTime.Add(time.Duration(int(time.Second)*tc.args.timeElapsed))) + + // setup cdp state + suite.keeper.SetPreviousAccrualTime(suite.ctx, tc.args.ctype, suite.ctx.BlockTime()) + suite.keeper.SetInterestFactor(suite.ctx, tc.args.ctype, sdk.OneDec()) + err = suite.keeper.AddCdp(suite.ctx, addrs[0], tc.args.initialCollateral, tc.args.initialPrincipal, tc.args.ctype) + suite.Require().NoError(err) + + updatedBlockTime := suite.ctx.BlockTime().Add(time.Duration(int(time.Second) * tc.args.timeElapsed)) + suite.ctx = suite.ctx.WithBlockTime(updatedBlockTime) + err = suite.keeper.AccumulateInterest(suite.ctx, tc.args.ctype) + suite.Require().NoError(err) + + cdp, found := suite.keeper.GetCDP(suite.ctx, tc.args.ctype, 1) + suite.Require().True(found) + + newInterest := suite.keeper.CalculateNewInterest(suite.ctx, cdp) + + suite.Require().Equal(tc.args.expectedFees, newInterest) + + }) + } +} + +func (suite *InterestTestSuite) TestSyncInterestForRiskyCDPs() { + type args struct { + ctype string + numberCdps int + slice int + initialCollateral sdk.Coin + minPrincipal sdk.Coin + principalIncrement sdk.Coin + initialTime time.Time + timeElapsed int + expectedCDPs int + } + + type test struct { + name string + args args + } + + oneYearInSeconds := 31536000 + testCases := []test{ + + { + "1 year", + args{ + ctype: "bnb-a", + numberCdps: 20, + slice: 10, + initialCollateral: c("bnb", 100000000000), + minPrincipal: c("usdx", 100000000), + principalIncrement: c("usdx", 10000000), + initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + timeElapsed: oneYearInSeconds, + expectedCDPs: 10, + }, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() + suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime) + // setup account state + _, addrs := app.GeneratePrivKeyAddressPairs(tc.args.numberCdps) + ak := suite.app.GetAccountKeeper() + sk := suite.app.GetSupplyKeeper() + for _, addr := range addrs { + acc := ak.NewAccountWithAddress(suite.ctx, addr) + ak.SetAccount(suite.ctx, acc) + err := sk.MintCoins(suite.ctx, types.ModuleName, cs(tc.args.initialCollateral)) + suite.Require().NoError(err) + err = sk.SendCoinsFromModuleToAccount(suite.ctx, types.ModuleName, addr, cs(tc.args.initialCollateral)) + suite.Require().NoError(err) + } + // setup pricefeed + pk := suite.app.GetPriceFeedKeeper() + pk.SetPrice(suite.ctx, sdk.AccAddress{}, "bnb:usd", d("20.0"), tc.args.initialTime.Add(time.Duration(int(time.Second)*tc.args.timeElapsed))) + + // setup cdp state + suite.keeper.SetPreviousAccrualTime(suite.ctx, tc.args.ctype, suite.ctx.BlockTime()) + suite.keeper.SetInterestFactor(suite.ctx, tc.args.ctype, sdk.OneDec()) + for j, addr := range addrs { + initialPrincipal := tc.args.minPrincipal.Add(c("usdx", int64(j)*tc.args.principalIncrement.Amount.Int64())) + err := suite.keeper.AddCdp(suite.ctx, addr, tc.args.initialCollateral, initialPrincipal, tc.args.ctype) + suite.Require().NoError(err) + } + + updatedBlockTime := suite.ctx.BlockTime().Add(time.Duration(int(time.Second) * tc.args.timeElapsed)) + suite.ctx = suite.ctx.WithBlockTime(updatedBlockTime) + err := suite.keeper.AccumulateInterest(suite.ctx, tc.args.ctype) + suite.Require().NoError(err) + + err = suite.keeper.SynchronizeInterestForRiskyCDPs(suite.ctx, i(int64(tc.args.slice)), sdk.MaxSortableDec, tc.args.ctype) + suite.Require().NoError(err) + + cdpsUpdatedCount := 0 + + for _, addr := range addrs { + cdp, found := suite.keeper.GetCdpByOwnerAndCollateralType(suite.ctx, addr, tc.args.ctype) + suite.Require().True(found) + if cdp.FeesUpdated.Equal(suite.ctx.BlockTime()) { + cdpsUpdatedCount += 1 + } + } + suite.Require().Equal(tc.args.expectedCDPs, cdpsUpdatedCount) + }) + } +} + +func TestInterestTestSuite(t *testing.T) { + suite.Run(t, new(InterestTestSuite)) +} diff --git a/x/cdp/keeper/keeper.go b/x/cdp/keeper/keeper.go index 589e15e8..80bfb1c8 100644 --- a/x/cdp/keeper/keeper.go +++ b/x/cdp/keeper/keeper.go @@ -2,6 +2,7 @@ package keeper import ( "fmt" + "time" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/prefix" @@ -20,6 +21,7 @@ type Keeper struct { supplyKeeper types.SupplyKeeper auctionKeeper types.AuctionKeeper accountKeeper types.AccountKeeper + hooks types.CDPHooks maccPerms map[string][]string } @@ -38,10 +40,20 @@ func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, paramstore subspace.Subspace, auctionKeeper: ak, supplyKeeper: sk, accountKeeper: ack, + hooks: nil, maccPerms: maccs, } } +// SetHooks sets the cdp keeper hooks +func (k *Keeper) SetHooks(hooks types.CDPHooks) *Keeper { + if k.hooks != nil { + panic("cannot set validator hooks twice") + } + k.hooks = hooks + return k +} + // CdpDenomIndexIterator returns an sdk.Iterator for all cdps with matching collateral denom func (k Keeper) CdpDenomIndexIterator(ctx sdk.Context, collateralType string) sdk.Iterator { store := prefix.NewStore(ctx.KVStore(k.key), types.CdpKeyPrefix) @@ -111,22 +123,105 @@ func (k Keeper) IterateCdpsByCollateralRatio(ctx sdk.Context, collateralType str } } -// SetSavingsRateDistributed sets the SavingsRateDistributed in the store -func (k Keeper) SetSavingsRateDistributed(ctx sdk.Context, totalDistributed sdk.Int) { - store := prefix.NewStore(ctx.KVStore(k.key), types.SavingsRateDistributedKey) - bz := k.cdc.MustMarshalBinaryLengthPrefixed(totalDistributed) - store.Set([]byte{}, bz) +// GetSliceOfCDPsByRatioAndType returns a slice of cdps of size equal to the input cutoffCount +// sorted by target ratio in ascending order (ie, the lowest collateral:debt ratio cdps are returned first) +func (k Keeper) GetSliceOfCDPsByRatioAndType(ctx sdk.Context, cutoffCount sdk.Int, targetRatio sdk.Dec, collateralType string) (cdps types.CDPs) { + count := sdk.ZeroInt() + k.IterateCdpsByCollateralRatio(ctx, collateralType, targetRatio, func(cdp types.CDP) bool { + cdps = append(cdps, cdp) + count = count.Add(sdk.OneInt()) + if count.GTE(cutoffCount) { + return true + } + return false + }) + return cdps } -// GetSavingsRateDistributed gets the SavingsRateDistributed from the store -func (k Keeper) GetSavingsRateDistributed(ctx sdk.Context) sdk.Int { - savingsRateDistributed := sdk.ZeroInt() - store := prefix.NewStore(ctx.KVStore(k.key), types.SavingsRateDistributedKey) - bz := store.Get([]byte{}) +// GetPreviousAccrualTime returns the last time an individual market accrued interest +func (k Keeper) GetPreviousAccrualTime(ctx sdk.Context, ctype string) (time.Time, bool) { + store := prefix.NewStore(ctx.KVStore(k.key), types.PreviousAccrualTimePrefix) + bz := store.Get([]byte(ctype)) if bz == nil { - return savingsRateDistributed + return time.Time{}, false } - - k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &savingsRateDistributed) - return savingsRateDistributed + var previousAccrualTime time.Time + k.cdc.MustUnmarshalBinaryBare(bz, &previousAccrualTime) + return previousAccrualTime, true +} + +// SetPreviousAccrualTime sets the most recent accrual time for a particular market +func (k Keeper) SetPreviousAccrualTime(ctx sdk.Context, ctype string, previousAccrualTime time.Time) { + store := prefix.NewStore(ctx.KVStore(k.key), types.PreviousAccrualTimePrefix) + bz := k.cdc.MustMarshalBinaryBare(previousAccrualTime) + store.Set([]byte(ctype), bz) +} + +// GetInterestFactor returns the current interest factor for an individual collateral type +func (k Keeper) GetInterestFactor(ctx sdk.Context, ctype string) (sdk.Dec, bool) { + store := prefix.NewStore(ctx.KVStore(k.key), types.InterestFactorPrefix) + bz := store.Get([]byte(ctype)) + if bz == nil { + return sdk.ZeroDec(), false + } + var interestFactor sdk.Dec + k.cdc.MustUnmarshalBinaryBare(bz, &interestFactor) + return interestFactor, true +} + +// SetInterestFactor sets the current interest factor for an individual collateral type +func (k Keeper) SetInterestFactor(ctx sdk.Context, ctype string, interestFactor sdk.Dec) { + store := prefix.NewStore(ctx.KVStore(k.key), types.InterestFactorPrefix) + bz := k.cdc.MustMarshalBinaryBare(interestFactor) + store.Set([]byte(ctype), bz) +} + +// IncrementTotalPrincipal increments the total amount of debt that has been drawn with that collateral type +func (k Keeper) IncrementTotalPrincipal(ctx sdk.Context, collateralType string, principal sdk.Coin) { + total := k.GetTotalPrincipal(ctx, collateralType, principal.Denom) + total = total.Add(principal.Amount) + k.SetTotalPrincipal(ctx, collateralType, principal.Denom, total) +} + +// DecrementTotalPrincipal decrements the total amount of debt that has been drawn for a particular collateral type +func (k Keeper) DecrementTotalPrincipal(ctx sdk.Context, collateralType string, principal sdk.Coin) { + total := k.GetTotalPrincipal(ctx, collateralType, principal.Denom) + // NOTE: negative total principal can happen in tests due to rounding errors + // in fee calculation + total = sdk.MaxInt(total.Sub(principal.Amount), sdk.ZeroInt()) + k.SetTotalPrincipal(ctx, collateralType, principal.Denom, total) +} + +// GetTotalPrincipal returns the total amount of principal that has been drawn for a particular collateral +func (k Keeper) GetTotalPrincipal(ctx sdk.Context, collateralType, principalDenom string) (total sdk.Int) { + store := prefix.NewStore(ctx.KVStore(k.key), types.PrincipalKeyPrefix) + bz := store.Get([]byte(collateralType + principalDenom)) + if bz == nil { + k.SetTotalPrincipal(ctx, collateralType, principalDenom, sdk.ZeroInt()) + return sdk.ZeroInt() + } + k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &total) + return total +} + +// SetTotalPrincipal sets the total amount of principal that has been drawn for the input collateral +func (k Keeper) SetTotalPrincipal(ctx sdk.Context, collateralType, principalDenom string, total sdk.Int) { + store := prefix.NewStore(ctx.KVStore(k.key), types.PrincipalKeyPrefix) + _, found := k.GetCollateralTypePrefix(ctx, collateralType) + if !found { + panic(fmt.Sprintf("collateral not found: %s", collateralType)) + } + store.Set([]byte(collateralType+principalDenom), k.cdc.MustMarshalBinaryLengthPrefixed(total)) +} + +// getModuleAccountCoins gets the total coin balance of this coin currently held by module accounts +func (k Keeper) getModuleAccountCoins(ctx sdk.Context, denom string) sdk.Coins { + totalModCoinBalance := sdk.NewCoins(sdk.NewCoin(denom, sdk.ZeroInt())) + for macc := range k.maccPerms { + modCoinBalance := k.supplyKeeper.GetModuleAccount(ctx, macc).GetCoins().AmountOf(denom) + if modCoinBalance.IsPositive() { + totalModCoinBalance = totalModCoinBalance.Add(sdk.NewCoin(denom, modCoinBalance)) + } + } + return totalModCoinBalance } diff --git a/x/cdp/keeper/keeper_test.go b/x/cdp/keeper/keeper_test.go index 551866be..c45ae67f 100644 --- a/x/cdp/keeper/keeper_test.go +++ b/x/cdp/keeper/keeper_test.go @@ -34,15 +34,3 @@ func (suite *KeeperTestSuite) ResetChain() { suite.ctx = ctx suite.keeper = keeper } - -func (suite *KeeperTestSuite) TestGetSetSavingsRateDistributed() { - suite.ResetChain() - - // Set savings rate distributed value - savingsRateDist := sdk.NewInt(555000555000) - suite.keeper.SetSavingsRateDistributed(suite.ctx, savingsRateDist) - - // Check store's savings rate distributed value - s := suite.keeper.GetSavingsRateDistributed(suite.ctx) - suite.Equal(savingsRateDist, s) -} diff --git a/x/cdp/keeper/querier.go b/x/cdp/keeper/querier.go index 09f9b7aa..5545c997 100644 --- a/x/cdp/keeper/querier.go +++ b/x/cdp/keeper/querier.go @@ -1,8 +1,6 @@ package keeper import ( - "fmt" - abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/client" @@ -32,10 +30,6 @@ func NewQuerier(keeper Keeper) sdk.Querier { return queryGetParams(ctx, req, keeper) case types.QueryGetAccounts: return queryGetAccounts(ctx, req, keeper) - case types.QueryGetSavingsRateDistributed: - return queryGetSavingsRateDistributed(ctx, req, keeper) - case types.QueryGetPreviousSavingsDistributionTime: - return queryGetPreviousSavingsDistributionTime(ctx, req, keeper) default: return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown %s query endpoint %s", types.ModuleName, path[0]) } @@ -172,12 +166,10 @@ func queryGetParams(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]by func queryGetAccounts(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, error) { cdpAccAccount := keeper.supplyKeeper.GetModuleAccount(ctx, types.ModuleName) liquidatorAccAccount := keeper.supplyKeeper.GetModuleAccount(ctx, types.LiquidatorMacc) - savingsRateAccAccount := keeper.supplyKeeper.GetModuleAccount(ctx, types.SavingsRateMacc) accounts := []supply.ModuleAccount{ *cdpAccAccount.(*supply.ModuleAccount), *liquidatorAccAccount.(*supply.ModuleAccount), - *savingsRateAccAccount.(*supply.ModuleAccount), } // Encode results @@ -188,36 +180,6 @@ func queryGetAccounts(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([] return bz, nil } -// query get savings rate distributed in the cdp store -func queryGetSavingsRateDistributed(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, error) { - // Get savings rate distributed - savingsRateDist := keeper.GetSavingsRateDistributed(ctx) - - // Encode results - bz, err := codec.MarshalJSONIndent(types.ModuleCdc, savingsRateDist) - if err != nil { - return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) - } - return bz, nil -} - -// query get savings rate distributed in the cdp store -func queryGetPreviousSavingsDistributionTime(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, error) { - // Get savings rate distributed - savingsRateDistTime, found := keeper.GetPreviousSavingsDistribution(ctx) - - if !found { - return nil, fmt.Errorf("previous distribution time not found") - } - - // Encode results - bz, err := codec.MarshalJSONIndent(types.ModuleCdc, savingsRateDistTime) - if err != nil { - return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) - } - return bz, nil -} - // query cdps in store and filter by request params func queryGetCdps(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, error) { var params types.QueryCdpsParams diff --git a/x/cdp/keeper/querier_test.go b/x/cdp/keeper/querier_test.go index f52c6c74..b5d40062 100644 --- a/x/cdp/keeper/querier_test.go +++ b/x/cdp/keeper/querier_test.go @@ -287,7 +287,7 @@ func (suite *QuerierTestSuite) TestQueryAccounts() { var accounts []supply.ModuleAccount suite.Require().Nil(supply.ModuleCdc.UnmarshalJSON(bz, &accounts)) - suite.Require().Equal(3, len(accounts)) + suite.Require().Equal(2, len(accounts)) findByName := func(name string) bool { for _, account := range accounts { @@ -300,18 +300,6 @@ func (suite *QuerierTestSuite) TestQueryAccounts() { suite.Require().True(findByName("cdp")) suite.Require().True(findByName("liquidator")) - suite.Require().True(findByName("savings")) -} - -func (suite *QuerierTestSuite) TestQuerySavingsRateDistributed() { - ctx := suite.ctx.WithIsCheckTx(false) - bz, err := suite.querier(ctx, []string{types.QueryGetSavingsRateDistributed}, abci.RequestQuery{}) - suite.Nil(err) - suite.NotNil(bz) - - var distAmount sdk.Int - suite.Nil(types.ModuleCdc.UnmarshalJSON(bz, &distAmount)) - suite.True(sdk.ZeroInt().Equal(distAmount)) } func (suite *QuerierTestSuite) TestFindIntersection() { diff --git a/x/cdp/keeper/savings.go b/x/cdp/keeper/savings.go deleted file mode 100644 index 779507f0..00000000 --- a/x/cdp/keeper/savings.go +++ /dev/null @@ -1,106 +0,0 @@ -package keeper - -import ( - "time" - - "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" - supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported" - - "github.com/kava-labs/kava/x/cdp/types" -) - -// 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) error { - dp, found := k.GetDebtParam(ctx, debtDenom) - if !found { - return sdkerrors.Wrap(types.ErrDebtNotSupported, debtDenom) - } - - savingsRateMacc := k.supplyKeeper.GetModuleAccount(ctx, types.SavingsRateMacc) - surplusToDistribute := savingsRateMacc.GetCoins().AmountOf(dp.Denom) - if surplusToDistribute.IsZero() { - return nil - } - - modAccountCoins := k.getModuleAccountCoins(ctx, dp.Denom) - totalSupplyLessModAccounts := k.supplyKeeper.GetSupply(ctx).GetTotal().Sub(modAccountCoins) - - // values to use in interest calculation - totalSurplus := sdk.NewDecFromInt(surplusToDistribute) - totalSupply := sdk.NewDecFromInt(totalSupplyLessModAccounts.AmountOf(debtDenom)) - - var iterationErr error - // TODO: avoid iterating over all the accounts by keeping the stored stable coin - // holders' addresses separately. - k.accountKeeper.IterateAccounts(ctx, func(acc authexported.Account) (stop bool) { - _, ok := acc.(supplyexported.ModuleAccountI) - if ok { - // don't distribute savings rate to module accounts - return false - } - - debtAmount := acc.GetCoins().AmountOf(debtDenom) - if !debtAmount.IsPositive() { - return false - } - - // (balance * rewardToDisribute) / totalSupply - // interest is the ratable fraction of savings rate owed to that account, rounded using bankers rounding - interest := (sdk.NewDecFromInt(debtAmount).Mul(totalSurplus)).Quo(totalSupply).RoundInt() - // sanity check, if we are going to over-distribute due to rounding, distribute only the remaining savings rate that hasn't been distributed. - interest = sdk.MinInt(interest, surplusToDistribute) - - // sanity check - don't send saving rate if the rounded amount is zero - if !interest.IsPositive() { - return false - } - - // update total savings rate distributed by surplus to distribute - previousSavingsDistributed := k.GetSavingsRateDistributed(ctx) - newTotalDistributed := previousSavingsDistributed.Add(interest) - k.SetSavingsRateDistributed(ctx, newTotalDistributed) - - interestCoins := sdk.NewCoins(sdk.NewCoin(debtDenom, interest)) - err := k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.SavingsRateMacc, acc.GetAddress(), interestCoins) - if err != nil { - iterationErr = err - return true - } - surplusToDistribute = surplusToDistribute.Sub(interest) - return false - }) - - return iterationErr -} - -// GetPreviousSavingsDistribution get the time of the previous savings rate distribution -func (k Keeper) GetPreviousSavingsDistribution(ctx sdk.Context) (distTime time.Time, found bool) { - store := prefix.NewStore(ctx.KVStore(k.key), types.PreviousDistributionTimeKey) - b := store.Get([]byte{}) - if b == nil { - return time.Time{}, false - } - k.cdc.MustUnmarshalBinaryLengthPrefixed(b, &distTime) - return distTime, true -} - -// SetPreviousSavingsDistribution set the time of the previous block -func (k Keeper) SetPreviousSavingsDistribution(ctx sdk.Context, distTime time.Time) { - store := prefix.NewStore(ctx.KVStore(k.key), types.PreviousDistributionTimeKey) - store.Set([]byte{}, k.cdc.MustMarshalBinaryLengthPrefixed(distTime)) -} - -// getModuleAccountCoins gets the total coin balance of this coin currently held by module accounts -func (k Keeper) getModuleAccountCoins(ctx sdk.Context, denom string) sdk.Coins { - totalModCoinBalance := sdk.NewCoins(sdk.NewCoin(denom, sdk.ZeroInt())) - for macc := range k.maccPerms { - modCoinBalance := k.supplyKeeper.GetModuleAccount(ctx, macc).GetCoins().AmountOf(denom) - if modCoinBalance.IsPositive() { - totalModCoinBalance = totalModCoinBalance.Add(sdk.NewCoin(denom, modCoinBalance)) - } - } - return totalModCoinBalance -} diff --git a/x/cdp/keeper/savings_test.go b/x/cdp/keeper/savings_test.go deleted file mode 100644 index 957fb994..00000000 --- a/x/cdp/keeper/savings_test.go +++ /dev/null @@ -1,113 +0,0 @@ -package keeper_test - -import ( - "testing" - - "github.com/stretchr/testify/suite" - - sdk "github.com/cosmos/cosmos-sdk/types" - - abci "github.com/tendermint/tendermint/abci/types" - tmtime "github.com/tendermint/tendermint/types/time" - - "github.com/kava-labs/kava/app" - "github.com/kava-labs/kava/x/cdp/keeper" - "github.com/kava-labs/kava/x/cdp/types" -) - -type SavingsTestSuite struct { - suite.Suite - - keeper keeper.Keeper - app app.TestApp - ctx sdk.Context - addrs []sdk.AccAddress - amountToDistribute int64 -} - -func (suite *SavingsTestSuite) SetupTest() { - tApp := app.NewTestApp() - ctx := tApp.NewContext(true, abci.Header{Height: 1, Time: tmtime.Now()}) - - _, addrs := app.GeneratePrivKeyAddressPairs(3) - authGS := app.NewAuthGenState( - addrs, - []sdk.Coins{ - cs(c("usdx", 100000)), cs(c("usdx", 50000)), cs(c("usdx", 50000)), - }, - ) - - tApp.InitializeFromGenesisStates( - authGS, - NewPricefeedGenStateMulti(), - NewCDPGenStateMulti(), - ) - - sk := tApp.GetSupplyKeeper() - macc := sk.GetModuleAccount(ctx, types.SavingsRateMacc) - distAmount := int64(10000) - err := sk.MintCoins(ctx, macc.GetName(), cs(c("usdx", distAmount))) - suite.NoError(err) - - keeper := tApp.GetCDPKeeper() - suite.app = tApp - suite.keeper = keeper - suite.ctx = ctx - suite.addrs = addrs - suite.amountToDistribute = distAmount -} - -func (suite *SavingsTestSuite) TestApplySavingsRate() { - preSavingsRateDistAmount := suite.keeper.GetSavingsRateDistributed(suite.ctx) - - err := suite.keeper.DistributeSavingsRate(suite.ctx, "usdx") - suite.NoError(err) - - ak := suite.app.GetAccountKeeper() - acc0 := ak.GetAccount(suite.ctx, suite.addrs[0]) - suite.Equal(cs(c("usdx", 105000)), acc0.GetCoins()) - acc1 := ak.GetAccount(suite.ctx, suite.addrs[1]) - suite.Equal(cs(c("usdx", 52500)), acc1.GetCoins()) - acc2 := ak.GetAccount(suite.ctx, suite.addrs[2]) - suite.Equal(cs(c("usdx", 52500)), acc2.GetCoins()) - - sk := suite.app.GetSupplyKeeper() - macc := sk.GetModuleAccount(suite.ctx, types.SavingsRateMacc) - suite.True(macc.GetCoins().AmountOf("usdx").IsZero()) - - expectedPostSavingsRateDistAmount := preSavingsRateDistAmount.Add(sdk.NewInt(suite.amountToDistribute)) - postSavingsRateDistAmount := suite.keeper.GetSavingsRateDistributed(suite.ctx) - suite.True(expectedPostSavingsRateDistAmount.Equal(postSavingsRateDistAmount)) -} - -func (suite *SavingsTestSuite) TestGetSetPreviousDistributionTime() { - now := tmtime.Now() - - _, f := suite.keeper.GetPreviousSavingsDistribution(suite.ctx) - suite.Require().False(f) // distr time not set at genesis when the default genesis is used - - suite.NotPanics(func() { suite.keeper.SetPreviousSavingsDistribution(suite.ctx, now) }) - - pdt, f := suite.keeper.GetPreviousSavingsDistribution(suite.ctx) - suite.True(f) - suite.Equal(now, pdt) -} - -func (suite *SavingsTestSuite) TestGetSetSavingsRateDistributed() { - // Savings rate dist set to 0 when the default genesis is used - preSavingsRateDistAmount := suite.keeper.GetSavingsRateDistributed(suite.ctx) - suite.True(preSavingsRateDistAmount.Equal(types.DefaultSavingsRateDistributed)) - - // Adding new dist amount to existing dist so default genesis value can be updated in the future - amountToDistribute := sdk.NewInt(9876543210) - newTotalDistributed := preSavingsRateDistAmount.Add(amountToDistribute) - - suite.NotPanics(func() { suite.keeper.SetSavingsRateDistributed(suite.ctx, newTotalDistributed) }) - - postSavingsRateDistAmount := suite.keeper.GetSavingsRateDistributed(suite.ctx) - suite.Equal(newTotalDistributed, postSavingsRateDistAmount) -} - -func TestSavingsTestSuite(t *testing.T) { - suite.Run(t, new(SavingsTestSuite)) -} diff --git a/x/cdp/keeper/seize.go b/x/cdp/keeper/seize.go index c6bb77d7..b2971e84 100644 --- a/x/cdp/keeper/seize.go +++ b/x/cdp/keeper/seize.go @@ -4,10 +4,33 @@ 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" ) +// AttemptKeeperLiquidation liquidates the cdp with the input collateral type and owner if it is below the required collateralization ratio +// if the cdp is liquidated, the keeper that sent the transaction is rewarded a percentage of the collateral according to that collateral types' +// keeper reward percentage. +func (k Keeper) AttemptKeeperLiquidation(ctx sdk.Context, keeper, owner sdk.AccAddress, collateralType string) error { + cdp, found := k.GetCdpByOwnerAndCollateralType(ctx, owner, collateralType) + if !found { + return sdkerrors.Wrapf(types.ErrCdpNotFound, "owner %s, denom %s", owner, collateralType) + } + k.hooks.BeforeCDPModified(ctx, cdp) + cdp = k.SynchronizeInterest(ctx, cdp) + + err := k.ValidateLiquidation(ctx, cdp.Collateral, cdp.Type, cdp.Principal, cdp.AccumulatedFees) + if err != nil { + return err + } + cdp, err = k.payoutKeeperLiquidationReward(ctx, keeper, cdp) + if err != nil { + return err + } + return k.SeizeCollateral(ctx, cdp) +} + // SeizeCollateral liquidates the collateral in the input cdp. // the following operations are performed: // 1. Collateral for all deposits is sent from the cdp module to the liquidator module account @@ -79,6 +102,7 @@ func (k Keeper) LiquidateCdps(ctx sdk.Context, marketID string, collateralType s normalizedRatio := sdk.OneDec().Quo(priceDivLiqRatio) cdpsToLiquidate := k.GetAllCdpsByCollateralTypeAndRatio(ctx, collateralType, normalizedRatio) for _, c := range cdpsToLiquidate { + k.hooks.BeforeCDPModified(ctx, c) err := k.SeizeCollateral(ctx, c) if err != nil { return err @@ -93,7 +117,53 @@ func (k Keeper) ApplyLiquidationPenalty(ctx sdk.Context, collateralType string, return sdk.NewDecFromInt(debt).Mul(penalty).RoundInt() } +// ValidateLiquidation validate that adding the input principal puts the cdp below the liquidation ratio +func (k Keeper) ValidateLiquidation(ctx sdk.Context, collateral sdk.Coin, collateralType string, principal sdk.Coin, fees sdk.Coin) error { + collateralizationRatio, err := k.CalculateCollateralizationRatio(ctx, collateral, collateralType, principal, fees, spot) + if err != nil { + return err + } + liquidationRatio := k.getLiquidationRatio(ctx, collateralType) + if collateralizationRatio.GT(liquidationRatio) { + return sdkerrors.Wrapf(types.ErrNotLiquidatable, "collateral %s, collateral ratio %s, liquidation ratio %s", collateral.Denom, collateralizationRatio, liquidationRatio) + } + return nil +} + func (k Keeper) getModAccountDebt(ctx sdk.Context, accountName string) sdk.Int { macc := k.supplyKeeper.GetModuleAccount(ctx, accountName) return macc.GetCoins().AmountOf(k.GetDebtDenom(ctx)) } + +func (k Keeper) payoutKeeperLiquidationReward(ctx sdk.Context, keeper sdk.AccAddress, cdp types.CDP) (types.CDP, error) { + collateralParam, found := k.GetCollateral(ctx, cdp.Type) + if !found { + return types.CDP{}, sdkerrors.Wrapf(types.ErrInvalidCollateral, "%s", cdp.Type) + } + reward := cdp.Collateral.Amount.ToDec().Mul(collateralParam.KeeperRewardPercentage).RoundInt() + rewardCoin := sdk.NewCoin(cdp.Collateral.Denom, reward) + paidReward := false + deposits := k.GetDeposits(ctx, cdp.ID) + for _, dep := range deposits { + if dep.Amount.IsGTE(rewardCoin) { + dep.Amount = dep.Amount.Sub(rewardCoin) + k.SetDeposit(ctx, dep) + paidReward = true + break + } + } + if !paidReward { + return cdp, nil + } + err := k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, keeper, sdk.NewCoins(rewardCoin)) + if err != nil { + return types.CDP{}, err + } + cdp.Collateral = cdp.Collateral.Sub(rewardCoin) + ratio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Type, cdp.GetTotalPrincipal()) + err = k.UpdateCdpAndCollateralRatioIndex(ctx, cdp, ratio) + if err != nil { + return types.CDP{}, err + } + return cdp, nil +} diff --git a/x/cdp/keeper/seize_test.go b/x/cdp/keeper/seize_test.go index 64adc19b..12cf8a4a 100644 --- a/x/cdp/keeper/seize_test.go +++ b/x/cdp/keeper/seize_test.go @@ -3,6 +3,7 @@ package keeper_test import ( "errors" "math/rand" + "strings" "testing" "time" @@ -205,6 +206,258 @@ func (suite *SeizeTestSuite) TestApplyLiquidationPenalty() { suite.Panics(func() { suite.keeper.ApplyLiquidationPenalty(suite.ctx, "lol-a", i(1000)) }) } +func (suite *SeizeTestSuite) TestKeeperLiquidation() { + type args struct { + ctype string + blockTime time.Time + initialPrice sdk.Dec + finalPrice sdk.Dec + collateral sdk.Coin + principal sdk.Coin + expectedKeeperCoins sdk.Coins // additional coins (if any) the borrower address should have after successfully liquidating position + expectedAuctions auction.Auctions // the auctions we should expect to find have been started + } + + type errArgs struct { + expectLiquidate bool + contains string + } + + type test struct { + name string + args args + errArgs errArgs + } + + // Set up auction constants + layout := "2006-01-02T15:04:05.000Z" + endTimeStr := "9000-01-01T00:00:00.000Z" + endTime, _ := time.Parse(layout, endTimeStr) + addr, _ := sdk.AccAddressFromBech32("kava1ze7y9qwdddejmy7jlw4cymqqlt2wh05yhwmrv2") + + testCases := []test{ + { + "valid liquidation", + args{ + "btc-a", + time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + d("20000.00"), + d("19000.0"), + c("btc", 10000000), + c("usdx", 1333330000), + cs(c("btc", 100100000), c("xrp", 10000000000)), + auction.Auctions{ + auction.CollateralAuction{ + BaseAuction: auction.BaseAuction{ + ID: 1, + Initiator: "liquidator", + Lot: c("btc", 9900000), + Bidder: nil, + Bid: c("usdx", 0), + HasReceivedBids: false, + EndTime: endTime, + MaxEndTime: endTime, + }, + CorrespondingDebt: c("debt", 1333330000), + MaxBid: c("usdx", 1366663250), + LotReturns: auction.WeightedAddresses{[]sdk.AccAddress{addr}, []sdk.Int{sdk.NewInt(9900000)}}, + }, + }, + }, + errArgs{ + true, + "", + }, + }, + { + "invalid - not below collateralization ratio", + args{ + "btc-a", + time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + d("20000.00"), + d("21000.0"), + c("btc", 10000000), + c("usdx", 1333330000), + cs(), + auction.Auctions{}, + }, + errArgs{ + false, + "collateral ratio not below liquidation ratio", + }, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() + // setup pricefeed + pk := suite.app.GetPriceFeedKeeper() + _, err := pk.SetPrice(suite.ctx, sdk.AccAddress{}, "btc:usd", tc.args.initialPrice, suite.ctx.BlockTime().Add(time.Hour*24)) + suite.Require().NoError(err) + err = pk.SetCurrentPrices(suite.ctx, "btc:usd") + suite.Require().NoError(err) + + // setup cdp state + suite.keeper.SetPreviousAccrualTime(suite.ctx, tc.args.ctype, suite.ctx.BlockTime()) + suite.keeper.SetInterestFactor(suite.ctx, tc.args.ctype, sdk.OneDec()) + err = suite.keeper.AddCdp(suite.ctx, suite.addrs[0], tc.args.collateral, tc.args.principal, tc.args.ctype) + suite.Require().NoError(err) + + // update pricefeed + _, err = pk.SetPrice(suite.ctx, sdk.AccAddress{}, "btc:usd", tc.args.finalPrice, suite.ctx.BlockTime().Add(time.Hour*24)) + suite.Require().NoError(err) + err = pk.SetCurrentPrices(suite.ctx, "btc:usd") + suite.Require().NoError(err) + + _, found := suite.keeper.GetCdpByOwnerAndCollateralType(suite.ctx, suite.addrs[0], tc.args.ctype) + suite.Require().True(found) + + err = suite.keeper.AttemptKeeperLiquidation(suite.ctx, suite.addrs[1], suite.addrs[0], tc.args.ctype) + + if tc.errArgs.expectLiquidate { + suite.Require().NoError(err) + + _, found = suite.keeper.GetCdpByOwnerAndCollateralType(suite.ctx, suite.addrs[0], tc.args.ctype) + suite.Require().False(found) + + ak := suite.app.GetAuctionKeeper() + auctions := ak.GetAllAuctions(suite.ctx) + suite.Require().Equal(tc.args.expectedAuctions, auctions) + + ack := suite.app.GetAccountKeeper() + keeper := ack.GetAccount(suite.ctx, suite.addrs[1]) + suite.Require().Equal(tc.args.expectedKeeperCoins, keeper.GetCoins()) + } else { + suite.Require().Error(err) + suite.Require().True(strings.Contains(err.Error(), tc.errArgs.contains)) + } + }) + } +} + +func (suite *SeizeTestSuite) TestBeginBlockerLiquidation() { + type args struct { + ctype string + blockTime time.Time + initialPrice sdk.Dec + finalPrice sdk.Dec + collaterals sdk.Coins + principals sdk.Coins + expectedAuctions auction.Auctions // the auctions we should expect to find have been started + } + type errArgs struct { + expectLiquidate bool + contains string + } + type test struct { + name string + args args + errArgs errArgs + } + // Set up auction constants + layout := "2006-01-02T15:04:05.000Z" + endTimeStr := "9000-01-01T00:00:00.000Z" + endTime, _ := time.Parse(layout, endTimeStr) + addr, _ := sdk.AccAddressFromBech32("kava1ze7y9qwdddejmy7jlw4cymqqlt2wh05yhwmrv2") + + testCases := []test{ + { + "1 liquidation", + args{ + "btc-a", + time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + d("20000.00"), + d("10000.00"), + sdk.Coins{c("btc", 10000000), c("btc", 10000000)}, + sdk.Coins{c("usdx", 1000000000), c("usdx", 500000000)}, + auction.Auctions{ + auction.CollateralAuction{ + BaseAuction: auction.BaseAuction{ + ID: 1, + Initiator: "liquidator", + Lot: c("btc", 10000000), + Bidder: nil, + Bid: c("usdx", 0), + HasReceivedBids: false, + EndTime: endTime, + MaxEndTime: endTime, + }, + CorrespondingDebt: c("debt", 1000000000), + MaxBid: c("usdx", 1025000000), + LotReturns: auction.WeightedAddresses{[]sdk.AccAddress{addr}, []sdk.Int{sdk.NewInt(10000000)}}, + }, + }, + }, + errArgs{ + true, + "", + }, + }, + { + "no liquidation", + args{ + "btc-a", + time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + d("20000.00"), + d("10000.00"), + sdk.Coins{c("btc", 10000000), c("btc", 10000000)}, + sdk.Coins{c("usdx", 500000000), c("usdx", 500000000)}, + auction.Auctions{}, + }, + errArgs{ + false, + "collateral ratio not below liquidation ratio", + }, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() + // setup pricefeed + pk := suite.app.GetPriceFeedKeeper() + _, err := pk.SetPrice(suite.ctx, sdk.AccAddress{}, "btc:usd", tc.args.initialPrice, suite.ctx.BlockTime().Add(time.Hour*24)) + suite.Require().NoError(err) + err = pk.SetCurrentPrices(suite.ctx, "btc:usd") + suite.Require().NoError(err) + + // setup cdp state + suite.keeper.SetPreviousAccrualTime(suite.ctx, tc.args.ctype, suite.ctx.BlockTime()) + suite.keeper.SetInterestFactor(suite.ctx, tc.args.ctype, sdk.OneDec()) + + for idx, col := range tc.args.collaterals { + err := suite.keeper.AddCdp(suite.ctx, suite.addrs[idx], col, tc.args.principals[idx], tc.args.ctype) + suite.Require().NoError(err) + } + + // update pricefeed + _, err = pk.SetPrice(suite.ctx, sdk.AccAddress{}, "btc:usd", tc.args.finalPrice, suite.ctx.BlockTime().Add(time.Hour*24)) + suite.Require().NoError(err) + err = pk.SetCurrentPrices(suite.ctx, "btc:usd") + suite.Require().NoError(err) + + _ = suite.app.BeginBlocker(suite.ctx, abci.RequestBeginBlock{Header: suite.ctx.BlockHeader()}) + ak := suite.app.GetAuctionKeeper() + auctions := ak.GetAllAuctions(suite.ctx) + if tc.errArgs.expectLiquidate { + suite.Require().Equal(tc.args.expectedAuctions, auctions) + for _, a := range auctions { + ca := a.(auction.CollateralAuction) + _, found := suite.keeper.GetCdpByOwnerAndCollateralType(suite.ctx, ca.LotReturns.Addresses[0], tc.args.ctype) + suite.Require().False(found) + } + } else { + suite.Require().Equal(0, len(auctions)) + for idx, _ := range tc.args.collaterals { + _, found := suite.keeper.GetCdpByOwnerAndCollateralType(suite.ctx, suite.addrs[idx], tc.args.ctype) + suite.Require().True(found) + } + } + }) + } +} + func TestSeizeTestSuite(t *testing.T) { suite.Run(t, new(SeizeTestSuite)) } diff --git a/x/cdp/legacy/v0_11/types.go b/x/cdp/legacy/v0_11/types.go index e98f2461..787e02f4 100644 --- a/x/cdp/legacy/v0_11/types.go +++ b/x/cdp/legacy/v0_11/types.go @@ -8,12 +8,68 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + tmtime "github.com/tendermint/tendermint/types/time" ) +const ( + // ModuleName The name that will be used throughout the module + ModuleName = "cdp" + + // StoreKey Top level store key where all module items will be stored + StoreKey = ModuleName + + // RouterKey Top level router key + RouterKey = ModuleName + + // QuerierRoute Top level query string + QuerierRoute = ModuleName + + // DefaultParamspace default name for parameter store + DefaultParamspace = ModuleName + + // LiquidatorMacc module account for liquidator + LiquidatorMacc = "liquidator" + + // SavingsRateMacc module account for savings rate + SavingsRateMacc = "savings" +) + +// Parameter keys var ( - stabilityFeeMax = sdk.MustNewDecFromStr("1.000000051034942716") // 500% APR - minCollateralPrefix = 0 - maxCollateralPrefix = 255 + KeyGlobalDebtLimit = []byte("GlobalDebtLimit") + KeyCollateralParams = []byte("CollateralParams") + KeyDebtParam = []byte("DebtParam") + KeyDistributionFrequency = []byte("DistributionFrequency") + KeyCircuitBreaker = []byte("CircuitBreaker") + KeyDebtThreshold = []byte("DebtThreshold") + KeyDebtLot = []byte("DebtLot") + KeySurplusThreshold = []byte("SurplusThreshold") + KeySurplusLot = []byte("SurplusLot") + KeySavingsRateDistributed = []byte("SavingsRateDistributed") + DefaultGlobalDebt = sdk.NewCoin(DefaultStableDenom, sdk.ZeroInt()) + DefaultCircuitBreaker = false + DefaultCollateralParams = CollateralParams{} + DefaultDebtParam = DebtParam{ + Denom: "usdx", + ReferenceAsset: "usd", + ConversionFactor: sdk.NewInt(6), + DebtFloor: sdk.NewInt(10000000), + SavingsRate: sdk.MustNewDecFromStr("0.95"), + } + DefaultCdpStartingID = uint64(1) + DefaultDebtDenom = "debt" + DefaultGovDenom = "ukava" + DefaultStableDenom = "usdx" + DefaultSurplusThreshold = sdk.NewInt(500000000000) + DefaultDebtThreshold = sdk.NewInt(100000000000) + DefaultSurplusLot = sdk.NewInt(10000000000) + DefaultDebtLot = sdk.NewInt(10000000000) + DefaultPreviousDistributionTime = tmtime.Canonical(time.Unix(0, 0)) + DefaultSavingsDistributionFrequency = time.Hour * 12 + DefaultSavingsRateDistributed = sdk.NewInt(0) + minCollateralPrefix = 0 + maxCollateralPrefix = 255 + stabilityFeeMax = sdk.MustNewDecFromStr("1.000000051034942716") // 500% APR ) // CDP is the state of a single collateralized debt position. @@ -40,6 +96,19 @@ func NewCDP(id uint64, owner sdk.AccAddress, collateral sdk.Coin, collateralType } } +// NewCDPWithFees creates a new CDP object, for use during migration +func NewCDPWithFees(id uint64, owner sdk.AccAddress, collateral sdk.Coin, collateralType string, principal, fees sdk.Coin, time time.Time) CDP { + return CDP{ + ID: id, + Owner: owner, + Type: collateralType, + Collateral: collateral, + Principal: principal, + AccumulatedFees: fees, + FeesUpdated: time, + } +} + func (cdp CDP) Validate() error { if cdp.ID == 0 { return errors.New("cdp id cannot be 0") diff --git a/x/cdp/legacy/v0_13/types.go b/x/cdp/legacy/v0_13/types.go new file mode 100644 index 00000000..b9034bc1 --- /dev/null +++ b/x/cdp/legacy/v0_13/types.go @@ -0,0 +1,653 @@ +package v0_13 + +import ( + "errors" + "fmt" + "strings" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// Parameter keys +var ( + KeyGlobalDebtLimit = []byte("GlobalDebtLimit") + KeyCollateralParams = []byte("CollateralParams") + KeyDebtParam = []byte("DebtParam") + KeyCircuitBreaker = []byte("CircuitBreaker") + KeyDebtThreshold = []byte("DebtThreshold") + KeyDebtLot = []byte("DebtLot") + KeySurplusThreshold = []byte("SurplusThreshold") + KeySurplusLot = []byte("SurplusLot") + DefaultGlobalDebt = sdk.NewCoin(DefaultStableDenom, sdk.ZeroInt()) + DefaultCircuitBreaker = false + DefaultCollateralParams = CollateralParams{} + DefaultDebtParam = DebtParam{ + Denom: "usdx", + ReferenceAsset: "usd", + ConversionFactor: sdk.NewInt(6), + DebtFloor: sdk.NewInt(10000000), + } + DefaultCdpStartingID = uint64(1) + DefaultDebtDenom = "debt" + DefaultGovDenom = "ukava" + DefaultStableDenom = "usdx" + DefaultSurplusThreshold = sdk.NewInt(500000000000) + DefaultDebtThreshold = sdk.NewInt(100000000000) + DefaultSurplusLot = sdk.NewInt(10000000000) + DefaultDebtLot = sdk.NewInt(10000000000) + DefaultSavingsRateDistributed = sdk.NewInt(0) + minCollateralPrefix = 0 + maxCollateralPrefix = 255 + stabilityFeeMax = sdk.MustNewDecFromStr("1.000000051034942716") // 500% APR +) + +// GenesisState is the state that must be provided at genesis. +type GenesisState struct { + Params Params `json:"params" yaml:"params"` + CDPs CDPs `json:"cdps" yaml:"cdps"` + Deposits Deposits `json:"deposits" yaml:"deposits"` + StartingCdpID uint64 `json:"starting_cdp_id" yaml:"starting_cdp_id"` + DebtDenom string `json:"debt_denom" yaml:"debt_denom"` + GovDenom string `json:"gov_denom" yaml:"gov_denom"` + PreviousAccumulationTimes GenesisAccumulationTimes `json:"previous_accumulation_times" yaml:"previous_accumulation_times"` + TotalPrincipals GenesisTotalPrincipals `json:"total_principals" yaml:"total_principals"` +} + +// NewGenesisState returns a new genesis state +func NewGenesisState(params Params, cdps CDPs, deposits Deposits, startingCdpID uint64, + debtDenom, govDenom string, prevAccumTimes GenesisAccumulationTimes, + totalPrincipals GenesisTotalPrincipals) GenesisState { + return GenesisState{ + Params: params, + CDPs: cdps, + Deposits: deposits, + StartingCdpID: startingCdpID, + DebtDenom: debtDenom, + GovDenom: govDenom, + PreviousAccumulationTimes: prevAccumTimes, + TotalPrincipals: totalPrincipals, + } +} + +// Validate performs basic validation of genesis data returning an +// error for any failed validation criteria. +func (gs GenesisState) Validate() error { + + if err := gs.Params.Validate(); err != nil { + return err + } + + if err := gs.CDPs.Validate(); err != nil { + return err + } + + if err := gs.Deposits.Validate(); err != nil { + return err + } + + if err := gs.PreviousAccumulationTimes.Validate(); err != nil { + return err + } + + if err := gs.TotalPrincipals.Validate(); err != nil { + return err + } + + if err := sdk.ValidateDenom(gs.DebtDenom); err != nil { + return fmt.Errorf(fmt.Sprintf("debt denom invalid: %v", err)) + } + + if err := sdk.ValidateDenom(gs.GovDenom); err != nil { + return fmt.Errorf(fmt.Sprintf("gov denom invalid: %v", err)) + } + + return nil +} + +// GenesisAccumulationTime stores the previous distribution time and its corresponding denom +type GenesisAccumulationTime struct { + CollateralType string `json:"collateral_type" yaml:"collateral_type"` + PreviousAccumulationTime time.Time `json:"previous_accumulation_time" yaml:"previous_accumulation_time"` + InterestFactor sdk.Dec `json:"interest_factor" yaml:"interest_factor"` +} + +// NewGenesisAccumulationTime returns a new GenesisAccumulationTime +func NewGenesisAccumulationTime(ctype string, prevTime time.Time, factor sdk.Dec) GenesisAccumulationTime { + return GenesisAccumulationTime{ + CollateralType: ctype, + PreviousAccumulationTime: prevTime, + InterestFactor: factor, + } +} + +// GenesisAccumulationTimes slice of GenesisAccumulationTime +type GenesisAccumulationTimes []GenesisAccumulationTime + +// Validate performs validation of GenesisAccumulationTimes +func (gats GenesisAccumulationTimes) Validate() error { + for _, gat := range gats { + if err := gat.Validate(); err != nil { + return err + } + } + return nil +} + +// Validate performs validation of GenesisAccumulationTime +func (gat GenesisAccumulationTime) Validate() error { + if gat.InterestFactor.LT(sdk.OneDec()) { + return fmt.Errorf("interest factor should be ≥ 1.0, is %s for %s", gat.InterestFactor, gat.CollateralType) + } + return nil +} + +// GenesisTotalPrincipal stores the total principal and its corresponding collateral type +type GenesisTotalPrincipal struct { + CollateralType string `json:"collateral_type" yaml:"collateral_type"` + TotalPrincipal sdk.Int `json:"total_principal" yaml:"total_principal"` +} + +// NewGenesisTotalPrincipal returns a new GenesisTotalPrincipal +func NewGenesisTotalPrincipal(ctype string, principal sdk.Int) GenesisTotalPrincipal { + return GenesisTotalPrincipal{ + CollateralType: ctype, + TotalPrincipal: principal, + } +} + +// GenesisTotalPrincipals slice of GenesisTotalPrincipal +type GenesisTotalPrincipals []GenesisTotalPrincipal + +// Validate performs validation of GenesisTotalPrincipal +func (gtp GenesisTotalPrincipal) Validate() error { + if gtp.TotalPrincipal.IsNegative() { + return fmt.Errorf("total principal should be positive, is %s for %s", gtp.TotalPrincipal, gtp.CollateralType) + } + return nil +} + +// Validate performs validation of GenesisTotalPrincipals +func (gtps GenesisTotalPrincipals) Validate() error { + for _, gtp := range gtps { + if err := gtp.Validate(); err != nil { + return err + } + } + return nil +} + +// Params governance parameters for cdp module +type Params struct { + CollateralParams CollateralParams `json:"collateral_params" yaml:"collateral_params"` + DebtParam DebtParam `json:"debt_param" yaml:"debt_param"` + GlobalDebtLimit sdk.Coin `json:"global_debt_limit" yaml:"global_debt_limit"` + SurplusAuctionThreshold sdk.Int `json:"surplus_auction_threshold" yaml:"surplus_auction_threshold"` + SurplusAuctionLot sdk.Int `json:"surplus_auction_lot" yaml:"surplus_auction_lot"` + DebtAuctionThreshold sdk.Int `json:"debt_auction_threshold" yaml:"debt_auction_threshold"` + DebtAuctionLot sdk.Int `json:"debt_auction_lot" yaml:"debt_auction_lot"` + CircuitBreaker bool `json:"circuit_breaker" yaml:"circuit_breaker"` +} + +// NewParams returns a new params object +func NewParams( + debtLimit sdk.Coin, collateralParams CollateralParams, debtParam DebtParam, surplusThreshold, + surplusLot, debtThreshold, debtLot sdk.Int, breaker bool, +) Params { + return Params{ + GlobalDebtLimit: debtLimit, + CollateralParams: collateralParams, + DebtParam: debtParam, + SurplusAuctionThreshold: surplusThreshold, + SurplusAuctionLot: surplusLot, + DebtAuctionThreshold: debtThreshold, + DebtAuctionLot: debtLot, + CircuitBreaker: breaker, + } +} + +// CollateralParam governance parameters for each collateral type within the cdp module +type CollateralParam struct { + Denom string `json:"denom" yaml:"denom"` // Coin name of collateral type + Type string `json:"type" yaml:"type"` + LiquidationRatio sdk.Dec `json:"liquidation_ratio" yaml:"liquidation_ratio"` // The ratio (Collateral (priced in stable coin) / Debt) under which a CDP will be liquidated + DebtLimit sdk.Coin `json:"debt_limit" yaml:"debt_limit"` // Maximum amount of debt allowed to be drawn from this collateral type + StabilityFee sdk.Dec `json:"stability_fee" yaml:"stability_fee"` // per second stability fee for loans opened using this collateral + AuctionSize sdk.Int `json:"auction_size" yaml:"auction_size"` // Max amount of collateral to sell off in any one auction. + LiquidationPenalty sdk.Dec `json:"liquidation_penalty" yaml:"liquidation_penalty"` // percentage penalty (between [0, 1]) applied to a cdp if it is liquidated + Prefix byte `json:"prefix" yaml:"prefix"` + SpotMarketID string `json:"spot_market_id" yaml:"spot_market_id"` // marketID of the spot price of the asset from the pricefeed - used for opening CDPs, depositing, withdrawing + LiquidationMarketID string `json:"liquidation_market_id" yaml:"liquidation_market_id"` // marketID of the pricefeed used for liquidation + KeeperRewardPercentage sdk.Dec `json:"keeper_reward_percentage" yaml:"keeper_reward_percentage"` // the percentage of a CDPs collateral that gets rewarded to a keeper that liquidates the position + CheckCollateralizationIndexCount sdk.Int `json:"check_collateralization_index_count" yaml:"check_collateralization_index_count"` // the number of cdps that will be checked for liquidation in the begin blocker + ConversionFactor sdk.Int `json:"conversion_factor" yaml:"conversion_factor"` // factor for converting internal units to one base unit of collateral +} + +// NewCollateralParam returns a new CollateralParam +func NewCollateralParam( + denom, ctype string, liqRatio sdk.Dec, debtLimit sdk.Coin, stabilityFee sdk.Dec, auctionSize sdk.Int, + liqPenalty sdk.Dec, prefix byte, spotMarketID, liquidationMarketID string, keeperReward sdk.Dec, checkIndexCount sdk.Int, conversionFactor sdk.Int) CollateralParam { + return CollateralParam{ + Denom: denom, + Type: ctype, + LiquidationRatio: liqRatio, + DebtLimit: debtLimit, + StabilityFee: stabilityFee, + AuctionSize: auctionSize, + LiquidationPenalty: liqPenalty, + Prefix: prefix, + SpotMarketID: spotMarketID, + LiquidationMarketID: liquidationMarketID, + KeeperRewardPercentage: keeperReward, + CheckCollateralizationIndexCount: checkIndexCount, + ConversionFactor: conversionFactor, + } +} + +// String implements fmt.Stringer +func (cp CollateralParam) String() string { + return fmt.Sprintf(`Collateral: + Denom: %s + Type: %s + Liquidation Ratio: %s + Stability Fee: %s + Liquidation Penalty: %s + Debt Limit: %s + Auction Size: %s + Prefix: %b + Spot Market ID: %s + Liquidation Market ID: %s + Keeper Reward Percentage: %s + Check Collateralization Count: %s + Conversion Factor: %s`, + cp.Denom, cp.Type, cp.LiquidationRatio, cp.StabilityFee, cp.LiquidationPenalty, + cp.DebtLimit, cp.AuctionSize, cp.Prefix, cp.SpotMarketID, cp.LiquidationMarketID, + cp.KeeperRewardPercentage, cp.CheckCollateralizationIndexCount, cp.ConversionFactor) +} + +// CollateralParams array of CollateralParam +type CollateralParams []CollateralParam + +// String implements fmt.Stringer +func (cps CollateralParams) String() string { + out := "Collateral Params\n" + for _, cp := range cps { + out += fmt.Sprintf("%s\n", cp) + } + return out +} + +// DebtParam governance params for debt assets +type DebtParam struct { + Denom string `json:"denom" yaml:"denom"` + ReferenceAsset string `json:"reference_asset" yaml:"reference_asset"` + ConversionFactor sdk.Int `json:"conversion_factor" yaml:"conversion_factor"` + DebtFloor sdk.Int `json:"debt_floor" yaml:"debt_floor"` // minimum active loan size, used to prevent dust +} + +// NewDebtParam returns a new DebtParam +func NewDebtParam(denom, refAsset string, conversionFactor, debtFloor sdk.Int) DebtParam { + return DebtParam{ + Denom: denom, + ReferenceAsset: refAsset, + ConversionFactor: conversionFactor, + DebtFloor: debtFloor, + } +} + +// DebtParams array of DebtParam +type DebtParams []DebtParam + +// Validate checks that the parameters have valid values. +func (p Params) Validate() error { + if err := validateGlobalDebtLimitParam(p.GlobalDebtLimit); err != nil { + return err + } + + if err := validateCollateralParams(p.CollateralParams); err != nil { + return err + } + + if err := validateDebtParam(p.DebtParam); err != nil { + return err + } + + if err := validateCircuitBreakerParam(p.CircuitBreaker); err != nil { + return err + } + + if err := validateSurplusAuctionThresholdParam(p.SurplusAuctionThreshold); err != nil { + return err + } + + if err := validateSurplusAuctionLotParam(p.SurplusAuctionLot); err != nil { + return err + } + + if err := validateDebtAuctionThresholdParam(p.DebtAuctionThreshold); err != nil { + return err + } + + if err := validateDebtAuctionLotParam(p.DebtAuctionLot); err != nil { + return err + } + + if len(p.CollateralParams) == 0 { // default value OK + return nil + } + + if (DebtParam{}) != p.DebtParam { + if p.DebtParam.Denom != p.GlobalDebtLimit.Denom { + return fmt.Errorf("debt denom %s does not match global debt denom %s", + p.DebtParam.Denom, p.GlobalDebtLimit.Denom) + } + } + + // validate collateral params + collateralDupMap := make(map[string]int) + prefixDupMap := make(map[int]int) + collateralParamsDebtLimit := sdk.ZeroInt() + + for _, cp := range p.CollateralParams { + + prefix := int(cp.Prefix) + prefixDupMap[prefix] = 1 + collateralDupMap[cp.Denom] = 1 + + if cp.DebtLimit.Denom != p.GlobalDebtLimit.Denom { + return fmt.Errorf("collateral debt limit denom %s does not match global debt limit denom %s", + cp.DebtLimit.Denom, p.GlobalDebtLimit.Denom) + } + + collateralParamsDebtLimit = collateralParamsDebtLimit.Add(cp.DebtLimit.Amount) + + if cp.DebtLimit.Amount.GT(p.GlobalDebtLimit.Amount) { + return fmt.Errorf("collateral debt limit %s exceeds global debt limit: %s", cp.DebtLimit, p.GlobalDebtLimit) + } + } + + if collateralParamsDebtLimit.GT(p.GlobalDebtLimit.Amount) { + return fmt.Errorf("sum of collateral debt limits %s exceeds global debt limit %s", + collateralParamsDebtLimit, p.GlobalDebtLimit) + } + + return nil +} + +func validateGlobalDebtLimitParam(i interface{}) error { + globalDebtLimit, ok := i.(sdk.Coin) + 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) + } + + prefixDupMap := make(map[int]bool) + typeDupMap := make(map[string]bool) + for _, cp := range collateralParams { + if err := sdk.ValidateDenom(cp.Denom); err != nil { + return fmt.Errorf("collateral denom invalid %s", cp.Denom) + } + + if strings.TrimSpace(cp.SpotMarketID) == "" { + return fmt.Errorf("spot market id cannot be blank %s", cp) + } + + if strings.TrimSpace(cp.Type) == "" { + return fmt.Errorf("collateral type cannot be blank %s", cp) + } + + if strings.TrimSpace(cp.LiquidationMarketID) == "" { + return fmt.Errorf("liquidation market id 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] = true + + _, found = typeDupMap[cp.Type] + if found { + return fmt.Errorf("duplicate cdp collateral type: %s", cp.Type) + } + typeDupMap[cp.Type] = true + + if !cp.DebtLimit.IsValid() { + return fmt.Errorf("debt limit for all collaterals should be positive, is %s for %s", cp.DebtLimit, cp.Denom) + } + + 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) + } + if !cp.AuctionSize.IsPositive() { + return fmt.Errorf("auction size should be positive, is %s for %s", cp.AuctionSize, cp.Denom) + } + if cp.StabilityFee.LT(sdk.OneDec()) || cp.StabilityFee.GT(stabilityFeeMax) { + return fmt.Errorf("stability fee must be ≥ 1.0, ≤ %s, is %s for %s", stabilityFeeMax, cp.StabilityFee, cp.Denom) + } + if cp.KeeperRewardPercentage.IsNegative() || cp.KeeperRewardPercentage.GT(sdk.OneDec()) { + return fmt.Errorf("keeper reward percentage should be between 0 and 1, is %s for %s", cp.KeeperRewardPercentage, cp.Denom) + } + if cp.CheckCollateralizationIndexCount.IsNegative() { + return fmt.Errorf("keeper reward percentage should be positive, is %s for %s", cp.CheckCollateralizationIndexCount, cp.Denom) + } + } + + return nil +} + +func validateDebtParam(i interface{}) error { + debtParam, ok := i.(DebtParam) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + if err := sdk.ValidateDenom(debtParam.Denom); err != nil { + return fmt.Errorf("debt denom invalid %s", debtParam.Denom) + } + + 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 validateSurplusAuctionLotParam(i interface{}) error { + sal, ok := i.(sdk.Int) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if !sal.IsPositive() { + return fmt.Errorf("surplus auction lot should be positive: %s", sal) + } + + 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 validateDebtAuctionLotParam(i interface{}) error { + dal, ok := i.(sdk.Int) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if !dal.IsPositive() { + return fmt.Errorf("debt auction lot should be positive: %s", dal) + } + + return nil +} + +// CDP is the state of a single collateralized debt position. +type CDP struct { + ID uint64 `json:"id" yaml:"id"` // unique id for cdp + Owner sdk.AccAddress `json:"owner" yaml:"owner"` // Account that authorizes changes to the CDP + Type string `json:"type" yaml:"type"` // string representing the unique collateral type of the CDP + Collateral sdk.Coin `json:"collateral" yaml:"collateral"` // Amount of collateral stored in this CDP + Principal sdk.Coin `json:"principal" yaml:"principal"` // Amount of debt drawn using the CDP + AccumulatedFees sdk.Coin `json:"accumulated_fees" yaml:"accumulated_fees"` // Fees accumulated since the CDP was opened or debt was last repaid + FeesUpdated time.Time `json:"fees_updated" yaml:"fees_updated"` // The time when fees were last updated + InterestFactor sdk.Dec `json:"interest_factor" yaml:"interest_factor"` // the interest factor when fees were last calculated for this CDP +} + +// NewCDP creates a new CDP object +func NewCDP(id uint64, owner sdk.AccAddress, collateral sdk.Coin, collateralType string, principal sdk.Coin, time time.Time, interestFactor sdk.Dec) CDP { + fees := sdk.NewCoin(principal.Denom, sdk.ZeroInt()) + return CDP{ + ID: id, + Owner: owner, + Type: collateralType, + Collateral: collateral, + Principal: principal, + AccumulatedFees: fees, + FeesUpdated: time, + InterestFactor: interestFactor, + } +} + +// NewCDPWithFees creates a new CDP object, for use during migration +func NewCDPWithFees(id uint64, owner sdk.AccAddress, collateral sdk.Coin, collateralType string, principal, fees sdk.Coin, time time.Time, interestFactor sdk.Dec) CDP { + return CDP{ + ID: id, + Owner: owner, + Type: collateralType, + Collateral: collateral, + Principal: principal, + AccumulatedFees: fees, + FeesUpdated: time, + InterestFactor: interestFactor, + } +} + +// Validate performs a basic validation of the CDP fields. +func (cdp CDP) Validate() error { + if cdp.ID == 0 { + return errors.New("cdp id cannot be 0") + } + if cdp.Owner.Empty() { + return errors.New("cdp owner cannot be empty") + } + if !cdp.Collateral.IsValid() { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "collateral %s", cdp.Collateral) + } + if !cdp.Principal.IsValid() { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "principal %s", cdp.Principal) + } + if !cdp.AccumulatedFees.IsValid() { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "accumulated fees %s", cdp.AccumulatedFees) + } + if cdp.FeesUpdated.IsZero() { + return errors.New("cdp updated fee time cannot be zero") + } + if strings.TrimSpace(cdp.Type) == "" { + return fmt.Errorf("cdp type cannot be empty") + } + return nil +} + +// GetTotalPrincipal returns the total principle for the cdp +func (cdp CDP) GetTotalPrincipal() sdk.Coin { + return cdp.Principal.Add(cdp.AccumulatedFees) +} + +// CDPs a collection of CDP objects +type CDPs []CDP + +// Validate validates each CDP +func (cdps CDPs) Validate() error { + for _, cdp := range cdps { + if err := cdp.Validate(); err != nil { + return err + } + } + return nil +} + +// Deposit defines an amount of coins deposited by an account to a cdp +type Deposit struct { + CdpID uint64 `json:"cdp_id" yaml:"cdp_id"` // cdpID of the cdp + Depositor sdk.AccAddress `json:"depositor" yaml:"depositor"` // Address of the depositor + Amount sdk.Coin `json:"amount" yaml:"amount"` // Deposit amount +} + +// NewDeposit creates a new Deposit object +func NewDeposit(cdpID uint64, depositor sdk.AccAddress, amount sdk.Coin) Deposit { + return Deposit{cdpID, depositor, amount} +} + +// Validate performs a basic validation of the deposit fields. +func (d Deposit) Validate() error { + if d.CdpID == 0 { + return errors.New("deposit's cdp id cannot be 0") + } + if d.Depositor.Empty() { + return errors.New("depositor cannot be empty") + } + if !d.Amount.IsValid() { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "deposit %s", d.Amount) + } + return nil +} + +// Deposits a collection of Deposit objects +type Deposits []Deposit + +// Validate validates each deposit +func (ds Deposits) Validate() error { + for _, d := range ds { + if err := d.Validate(); err != nil { + return err + } + } + return nil +} diff --git a/x/cdp/legacy/v0_9/types.go b/x/cdp/legacy/v0_9/types.go index 52a243c2..ca7c35e7 100644 --- a/x/cdp/legacy/v0_9/types.go +++ b/x/cdp/legacy/v0_9/types.go @@ -4,12 +4,50 @@ import ( "time" sdk "github.com/cosmos/cosmos-sdk/types" + + tmtime "github.com/tendermint/tendermint/types/time" ) const ( ModuleName = "cdp" ) +// Parameter keys +var ( + KeyGlobalDebtLimit = []byte("GlobalDebtLimit") + KeyCollateralParams = []byte("CollateralParams") + KeyDebtParam = []byte("DebtParam") + KeyDistributionFrequency = []byte("DistributionFrequency") + KeyCircuitBreaker = []byte("CircuitBreaker") + KeyDebtThreshold = []byte("DebtThreshold") + KeyDebtLot = []byte("DebtLot") + KeySurplusThreshold = []byte("SurplusThreshold") + KeySurplusLot = []byte("SurplusLot") + DefaultGlobalDebt = sdk.NewCoin(DefaultStableDenom, sdk.ZeroInt()) + DefaultCircuitBreaker = false + DefaultCollateralParams = CollateralParams{} + DefaultDebtParam = DebtParam{ + Denom: "usdx", + ReferenceAsset: "usd", + ConversionFactor: sdk.NewInt(6), + DebtFloor: sdk.NewInt(10000000), + SavingsRate: sdk.MustNewDecFromStr("0.95"), + } + DefaultCdpStartingID = uint64(1) + DefaultDebtDenom = "debt" + DefaultGovDenom = "ukava" + DefaultStableDenom = "usdx" + DefaultSurplusThreshold = sdk.NewInt(500000000000) + DefaultDebtThreshold = sdk.NewInt(100000000000) + DefaultSurplusLot = sdk.NewInt(10000000000) + DefaultDebtLot = sdk.NewInt(10000000000) + DefaultPreviousDistributionTime = tmtime.Canonical(time.Unix(0, 0)) + DefaultSavingsDistributionFrequency = time.Hour * 12 + minCollateralPrefix = 0 + maxCollateralPrefix = 255 + stabilityFeeMax = sdk.MustNewDecFromStr("1.000000051034942716") // 500% APR +) + // CDP is the state of a single collateralized debt position. type CDP struct { ID uint64 `json:"id" yaml:"id"` // unique id for cdp diff --git a/x/cdp/simulation/decoder.go b/x/cdp/simulation/decoder.go index 91c89c10..cfd2c3e6 100644 --- a/x/cdp/simulation/decoder.go +++ b/x/cdp/simulation/decoder.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/binary" "fmt" - "time" "github.com/tendermint/tendermint/libs/kv" @@ -54,12 +53,6 @@ func DecodeStore(cdc *codec.Codec, kvA, kvB kv.Pair) string { cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &totalB) return fmt.Sprintf("%s\n%s", totalA, totalB) - case bytes.Equal(kvA.Key[:1], types.PreviousDistributionTimeKey): - var timeA, timeB time.Time - cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &timeA) - cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &timeB) - return fmt.Sprintf("%s\n%s", timeA, timeB) - default: panic(fmt.Sprintf("invalid %s key prefix %X", types.ModuleName, kvA.Key[:1])) } diff --git a/x/cdp/simulation/decoder_test.go b/x/cdp/simulation/decoder_test.go index 459d87d7..8aa0b583 100644 --- a/x/cdp/simulation/decoder_test.go +++ b/x/cdp/simulation/decoder_test.go @@ -32,7 +32,7 @@ func TestDecodeDistributionStore(t *testing.T) { deposit := types.Deposit{CdpID: 1, Amount: oneCoins} principal := sdk.OneInt() prevDistTime := time.Now().UTC() - cdp := types.CDP{ID: 1, FeesUpdated: prevDistTime, Collateral: oneCoins, Principal: oneCoins, AccumulatedFees: oneCoins} + cdp := types.CDP{ID: 1, FeesUpdated: prevDistTime, Collateral: oneCoins, Principal: oneCoins, AccumulatedFees: oneCoins, InterestFactor: sdk.OneDec()} kvPairs := kv.Pairs{ kv.Pair{Key: types.CdpIDKeyPrefix, Value: cdc.MustMarshalBinaryLengthPrefixed(cdpIds)}, @@ -43,7 +43,6 @@ func TestDecodeDistributionStore(t *testing.T) { 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.PreviousDistributionTimeKey), Value: cdc.MustMarshalBinaryLengthPrefixed(prevDistTime)}, kv.Pair{Key: []byte{0x99}, Value: []byte{0x99}}, } @@ -59,7 +58,6 @@ func TestDecodeDistributionStore(t *testing.T) { {"GovDenom", fmt.Sprintf("%s\n%s", denom, denom)}, {"DepositKeyPrefix", fmt.Sprintf("%v\n%v", deposit, deposit)}, {"Principal", fmt.Sprintf("%v\n%v", principal, principal)}, - {"PreviousDistributionTime", fmt.Sprintf("%s\n%s", prevDistTime, prevDistTime)}, {"other", ""}, } for i, tt := range tests { diff --git a/x/cdp/simulation/genesis.go b/x/cdp/simulation/genesis.go index 3baab9a0..095cd690 100644 --- a/x/cdp/simulation/genesis.go +++ b/x/cdp/simulation/genesis.go @@ -70,12 +70,11 @@ func randomCdpGenState(selection int) types.GenesisState { case 0: return types.GenesisState{ Params: types.Params{ - GlobalDebtLimit: sdk.NewInt64Coin("usdx", 100000000000000), - SurplusAuctionThreshold: types.DefaultSurplusThreshold, - SurplusAuctionLot: types.DefaultSurplusLot, - DebtAuctionLot: types.DefaultDebtLot, - DebtAuctionThreshold: types.DefaultDebtThreshold, - SavingsDistributionFrequency: types.DefaultSavingsDistributionFrequency, + GlobalDebtLimit: sdk.NewInt64Coin("usdx", 100000000000000), + SurplusAuctionThreshold: types.DefaultSurplusThreshold, + SurplusAuctionLot: types.DefaultSurplusLot, + DebtAuctionLot: types.DefaultDebtLot, + DebtAuctionThreshold: types.DefaultDebtThreshold, CollateralParams: types.CollateralParams{ { Denom: "xrp", @@ -122,24 +121,21 @@ func randomCdpGenState(selection int) types.GenesisState { ReferenceAsset: "usd", ConversionFactor: sdk.NewInt(6), DebtFloor: sdk.NewInt(10000000), - SavingsRate: sdk.MustNewDecFromStr("0.95"), }, }, - StartingCdpID: types.DefaultCdpStartingID, - DebtDenom: types.DefaultDebtDenom, - GovDenom: types.DefaultGovDenom, - CDPs: types.CDPs{}, - PreviousDistributionTime: types.DefaultPreviousDistributionTime, + StartingCdpID: types.DefaultCdpStartingID, + DebtDenom: types.DefaultDebtDenom, + GovDenom: types.DefaultGovDenom, + CDPs: types.CDPs{}, } case 1: return types.GenesisState{ Params: types.Params{ - GlobalDebtLimit: sdk.NewInt64Coin("usdx", 100000000000000), - SurplusAuctionThreshold: types.DefaultSurplusThreshold, - DebtAuctionThreshold: types.DefaultDebtThreshold, - SurplusAuctionLot: types.DefaultSurplusLot, - DebtAuctionLot: types.DefaultDebtLot, - SavingsDistributionFrequency: types.DefaultSavingsDistributionFrequency, + GlobalDebtLimit: sdk.NewInt64Coin("usdx", 100000000000000), + SurplusAuctionThreshold: types.DefaultSurplusThreshold, + DebtAuctionThreshold: types.DefaultDebtThreshold, + SurplusAuctionLot: types.DefaultSurplusLot, + DebtAuctionLot: types.DefaultDebtLot, CollateralParams: types.CollateralParams{ { Denom: "bnb", @@ -160,14 +156,12 @@ func randomCdpGenState(selection int) types.GenesisState { ReferenceAsset: "usd", ConversionFactor: sdk.NewInt(6), DebtFloor: sdk.NewInt(10000000), - SavingsRate: sdk.MustNewDecFromStr("0.95"), }, }, - StartingCdpID: types.DefaultCdpStartingID, - DebtDenom: types.DefaultDebtDenom, - GovDenom: types.DefaultGovDenom, - CDPs: types.CDPs{}, - PreviousDistributionTime: types.DefaultPreviousDistributionTime, + StartingCdpID: types.DefaultCdpStartingID, + DebtDenom: types.DefaultDebtDenom, + GovDenom: types.DefaultGovDenom, + CDPs: types.CDPs{}, } default: panic("invalid genesis state selector") diff --git a/x/cdp/simulation/operations.go b/x/cdp/simulation/operations.go index a88a0d15..38d71a86 100644 --- a/x/cdp/simulation/operations.go +++ b/x/cdp/simulation/operations.go @@ -184,12 +184,12 @@ func SimulateMsgCdp(ak types.AccountKeeper, k keeper.Keeper, pfk types.Pricefeed if shouldDraw(r) { collateralShifted := ShiftDec(sdk.NewDecFromInt(existingCDP.Collateral.Amount), randCollateralParam.ConversionFactor.Neg()) collateralValue := collateralShifted.Mul(priceShifted) - newFeesAccumulated := k.CalculateFees(ctx, existingCDP.Principal, sdk.NewInt(ctx.BlockTime().Unix()-existingCDP.FeesUpdated.Unix()), randCollateralParam.Type).Amount - totalFees := existingCDP.AccumulatedFees.Amount.Add(newFeesAccumulated) + newFeesAccumulated := k.CalculateNewInterest(ctx, existingCDP) + totalFees := existingCDP.AccumulatedFees.Add(newFeesAccumulated) // given the current collateral value, calculate how much debt we could add while maintaining a valid liquidation ratio - debt := existingCDP.Principal.Amount.Add(totalFees) + debt := existingCDP.Principal.Add(totalFees) maxTotalDebt := collateralValue.Quo(randCollateralParam.LiquidationRatio) - maxDebt := (maxTotalDebt.Sub(sdk.NewDecFromInt(debt))).Mul(sdk.MustNewDecFromStr("0.95")).TruncateInt() + maxDebt := (maxTotalDebt.Sub(sdk.NewDecFromInt(debt.Amount))).Mul(sdk.MustNewDecFromStr("0.95")).TruncateInt() if maxDebt.LTE(sdk.OneInt()) { // debt in cdp is maxed out return simulation.NewOperationMsgBasic(types.ModuleName, "no-operation", "cdp debt maxed out, cannot draw more debt", false, nil), nil, nil diff --git a/x/cdp/spec/02_state.md b/x/cdp/spec/02_state.md index 067e0bef..bdf36744 100644 --- a/x/cdp/spec/02_state.md +++ b/x/cdp/spec/02_state.md @@ -26,10 +26,12 @@ The CDP's collateral always equal to the total of the deposits. type CDP struct { ID uint64 Owner sdk.AccAddress + Type string Collateral sdk.Coin Principal sdk.Coin AccumulatedFees sdk.Coin FeesUpdated time.Time + InterestFactor sdk.Dec } ``` diff --git a/x/cdp/types/cdp.go b/x/cdp/types/cdp.go index 02ee32eb..e7f8ebfb 100644 --- a/x/cdp/types/cdp.go +++ b/x/cdp/types/cdp.go @@ -17,12 +17,13 @@ type CDP struct { Type string `json:"type" yaml:"type"` // string representing the unique collateral type of the CDP Collateral sdk.Coin `json:"collateral" yaml:"collateral"` // Amount of collateral stored in this CDP Principal sdk.Coin `json:"principal" yaml:"principal"` // Amount of debt drawn using the CDP - AccumulatedFees sdk.Coin `json:"accumulated_fees" yaml:"accumulated_fees"` // Fees accumulated since the CDP was opened or debt was last repayed - FeesUpdated time.Time `json:"fees_updated" yaml:"fees_updated"` // Amount of stable coin drawn from this CDP + AccumulatedFees sdk.Coin `json:"accumulated_fees" yaml:"accumulated_fees"` // Fees accumulated since the CDP was opened or debt was last repaid + FeesUpdated time.Time `json:"fees_updated" yaml:"fees_updated"` // The time when fees were last updated + InterestFactor sdk.Dec `json:"interest_factor" yaml:"interest_factor"` // the interest factor when fees were last calculated for this CDP } // NewCDP creates a new CDP object -func NewCDP(id uint64, owner sdk.AccAddress, collateral sdk.Coin, collateralType string, principal sdk.Coin, time time.Time) CDP { +func NewCDP(id uint64, owner sdk.AccAddress, collateral sdk.Coin, collateralType string, principal sdk.Coin, time time.Time, interestFactor sdk.Dec) CDP { fees := sdk.NewCoin(principal.Denom, sdk.ZeroInt()) return CDP{ ID: id, @@ -32,11 +33,12 @@ func NewCDP(id uint64, owner sdk.AccAddress, collateral sdk.Coin, collateralType Principal: principal, AccumulatedFees: fees, FeesUpdated: time, + InterestFactor: interestFactor, } } // NewCDPWithFees creates a new CDP object, for use during migration -func NewCDPWithFees(id uint64, owner sdk.AccAddress, collateral sdk.Coin, collateralType string, principal, fees sdk.Coin, time time.Time) CDP { +func NewCDPWithFees(id uint64, owner sdk.AccAddress, collateral sdk.Coin, collateralType string, principal, fees sdk.Coin, time time.Time, interestFactor sdk.Dec) CDP { return CDP{ ID: id, Owner: owner, @@ -45,6 +47,7 @@ func NewCDPWithFees(id uint64, owner sdk.AccAddress, collateral sdk.Coin, collat Principal: principal, AccumulatedFees: fees, FeesUpdated: time, + InterestFactor: interestFactor, } } @@ -57,7 +60,8 @@ func (cdp CDP) String() string { Collateral: %s Principal: %s AccumulatedFees: %s - Fees Last Updated: %s`, + Fees Last Updated: %s + Interest Factor: %s`, cdp.Owner, cdp.ID, cdp.Type, @@ -65,6 +69,7 @@ func (cdp CDP) String() string { cdp.Principal, cdp.AccumulatedFees, cdp.FeesUpdated, + cdp.InterestFactor, )) } @@ -139,6 +144,7 @@ func NewAugmentedCDP(cdp CDP, collateralValue sdk.Coin, collateralizationRatio s Principal: cdp.Principal, AccumulatedFees: cdp.AccumulatedFees, FeesUpdated: cdp.FeesUpdated, + InterestFactor: cdp.InterestFactor, }, CollateralValue: collateralValue, CollateralizationRatio: collateralizationRatio, @@ -157,6 +163,7 @@ func (augCDP AugmentedCDP) String() string { Principal: %s Fees: %s Fees Last Updated: %s + Interest Factor: %s Collateralization ratio: %s`, augCDP.Owner, augCDP.ID, @@ -166,6 +173,7 @@ func (augCDP AugmentedCDP) String() string { augCDP.Principal, augCDP.AccumulatedFees, augCDP.FeesUpdated, + augCDP.InterestFactor, augCDP.CollateralizationRatio, )) } diff --git a/x/cdp/types/cdp_test.go b/x/cdp/types/cdp_test.go index 2e346ada..86452d80 100644 --- a/x/cdp/types/cdp_test.go +++ b/x/cdp/types/cdp_test.go @@ -42,7 +42,7 @@ func (suite *CdpValidationSuite) TestCdpValidation() { }{ { name: "valid cdp", - cdp: types.NewCDP(1, suite.addrs[0], sdk.NewInt64Coin("bnb", 100000), "bnb-a", sdk.NewInt64Coin("usdx", 100000), tmtime.Now()), + cdp: types.NewCDP(1, suite.addrs[0], sdk.NewInt64Coin("bnb", 100000), "bnb-a", sdk.NewInt64Coin("usdx", 100000), tmtime.Now(), sdk.OneDec()), errArgs: errArgs{ expectPass: true, contains: "", @@ -50,7 +50,7 @@ func (suite *CdpValidationSuite) TestCdpValidation() { }, { name: "invalid cdp id", - cdp: types.NewCDP(0, suite.addrs[0], sdk.NewInt64Coin("bnb", 100000), "bnb-a", sdk.NewInt64Coin("usdx", 100000), tmtime.Now()), + cdp: types.NewCDP(0, suite.addrs[0], sdk.NewInt64Coin("bnb", 100000), "bnb-a", sdk.NewInt64Coin("usdx", 100000), tmtime.Now(), sdk.OneDec()), errArgs: errArgs{ expectPass: false, contains: "cdp id cannot be 0", @@ -58,7 +58,7 @@ func (suite *CdpValidationSuite) TestCdpValidation() { }, { name: "invalid collateral", - cdp: types.CDP{1, suite.addrs[0], "bnb-a", sdk.Coin{"", sdk.NewInt(100)}, sdk.Coin{"usdx", sdk.NewInt(100)}, sdk.Coin{"usdx", sdk.NewInt(0)}, tmtime.Now()}, + cdp: types.CDP{1, suite.addrs[0], "bnb-a", sdk.Coin{"", sdk.NewInt(100)}, sdk.Coin{"usdx", sdk.NewInt(100)}, sdk.Coin{"usdx", sdk.NewInt(0)}, tmtime.Now(), sdk.OneDec()}, errArgs: errArgs{ expectPass: false, contains: "invalid coins: collateral", @@ -66,7 +66,7 @@ func (suite *CdpValidationSuite) TestCdpValidation() { }, { name: "invalid prinicpal", - cdp: types.CDP{1, suite.addrs[0], "xrp-a", sdk.Coin{"xrp", sdk.NewInt(100)}, sdk.Coin{"", sdk.NewInt(100)}, sdk.Coin{"usdx", sdk.NewInt(0)}, tmtime.Now()}, + cdp: types.CDP{1, suite.addrs[0], "xrp-a", sdk.Coin{"xrp", sdk.NewInt(100)}, sdk.Coin{"", sdk.NewInt(100)}, sdk.Coin{"usdx", sdk.NewInt(0)}, tmtime.Now(), sdk.OneDec()}, errArgs: errArgs{ expectPass: false, contains: "invalid coins: principal", @@ -74,7 +74,7 @@ func (suite *CdpValidationSuite) TestCdpValidation() { }, { name: "invalid fees", - cdp: types.CDP{1, suite.addrs[0], "xrp-a", sdk.Coin{"xrp", sdk.NewInt(100)}, sdk.Coin{"usdx", sdk.NewInt(100)}, sdk.Coin{"", sdk.NewInt(0)}, tmtime.Now()}, + cdp: types.CDP{1, suite.addrs[0], "xrp-a", sdk.Coin{"xrp", sdk.NewInt(100)}, sdk.Coin{"usdx", sdk.NewInt(100)}, sdk.Coin{"", sdk.NewInt(0)}, tmtime.Now(), sdk.OneDec()}, errArgs: errArgs{ expectPass: false, contains: "invalid coins: accumulated fees", @@ -82,7 +82,7 @@ func (suite *CdpValidationSuite) TestCdpValidation() { }, { name: "invalid fees updated", - cdp: types.CDP{1, suite.addrs[0], "xrp-a", sdk.Coin{"xrp", sdk.NewInt(100)}, sdk.Coin{"usdx", sdk.NewInt(100)}, sdk.Coin{"usdx", sdk.NewInt(0)}, time.Time{}}, + cdp: types.CDP{1, suite.addrs[0], "xrp-a", sdk.Coin{"xrp", sdk.NewInt(100)}, sdk.Coin{"usdx", sdk.NewInt(100)}, sdk.Coin{"usdx", sdk.NewInt(0)}, time.Time{}, sdk.OneDec()}, errArgs: errArgs{ expectPass: false, contains: "cdp updated fee time cannot be zero", @@ -90,7 +90,7 @@ func (suite *CdpValidationSuite) TestCdpValidation() { }, { name: "invalid type", - cdp: types.CDP{1, suite.addrs[0], "", sdk.Coin{"xrp", sdk.NewInt(100)}, sdk.Coin{"usdx", sdk.NewInt(100)}, sdk.Coin{"usdx", sdk.NewInt(0)}, tmtime.Now()}, + cdp: types.CDP{1, suite.addrs[0], "", sdk.Coin{"xrp", sdk.NewInt(100)}, sdk.Coin{"usdx", sdk.NewInt(100)}, sdk.Coin{"usdx", sdk.NewInt(0)}, tmtime.Now(), sdk.OneDec()}, errArgs: errArgs{ expectPass: false, contains: "cdp type cannot be empty", diff --git a/x/cdp/types/errors.go b/x/cdp/types/errors.go index dec900da..f248a223 100644 --- a/x/cdp/types/errors.go +++ b/x/cdp/types/errors.go @@ -45,4 +45,10 @@ var ( ErrPricefeedDown = sdkerrors.Register(ModuleName, 19, "no price found for collateral") // ErrInvalidCollateral error for when the input collateral denom does not match the expected collateral denom ErrInvalidCollateral = sdkerrors.Register(ModuleName, 20, "invalid collateral for input collateral type") + // ErrAccountNotFound error for when no account is found for an input address + ErrAccountNotFound = sdkerrors.Register(ModuleName, 21, "account not found") + // ErrInsufficientBalance error for when an account does not have enough funds + ErrInsufficientBalance = sdkerrors.Register(ModuleName, 22, "insufficient balance") + // ErrNotLiquidatable error for when an cdp is not liquidatable + ErrNotLiquidatable = sdkerrors.Register(ModuleName, 23, "cdp collateral ratio not below liquidation ratio") ) diff --git a/x/cdp/types/expected_keepers.go b/x/cdp/types/expected_keepers.go index b960ed79..d16c7ebf 100644 --- a/x/cdp/types/expected_keepers.go +++ b/x/cdp/types/expected_keepers.go @@ -48,3 +48,9 @@ type AccountKeeper interface { IterateAccounts(ctx sdk.Context, cb func(account authexported.Account) (stop bool)) GetAccount(ctx sdk.Context, addr sdk.AccAddress) authexported.Account } + +// CDPHooks event hooks for other keepers to run code in response to CDP modifications +type CDPHooks interface { + AfterCDPCreated(ctx sdk.Context, cdp CDP) + BeforeCDPModified(ctx sdk.Context, cdp CDP) +} diff --git a/x/cdp/types/genesis.go b/x/cdp/types/genesis.go index edd4cb9c..4642e857 100644 --- a/x/cdp/types/genesis.go +++ b/x/cdp/types/genesis.go @@ -10,28 +10,29 @@ import ( // GenesisState is the state that must be provided at genesis. type GenesisState struct { - Params Params `json:"params" yaml:"params"` - CDPs CDPs `json:"cdps" yaml:"cdps"` - Deposits Deposits `json:"deposits" yaml:"deposits"` - StartingCdpID uint64 `json:"starting_cdp_id" yaml:"starting_cdp_id"` - DebtDenom string `json:"debt_denom" yaml:"debt_denom"` - GovDenom string `json:"gov_denom" yaml:"gov_denom"` - PreviousDistributionTime time.Time `json:"previous_distribution_time" yaml:"previous_distribution_time"` - SavingsRateDistributed sdk.Int `json:"savings_rate_distributed" yaml:"savings_rate_distributed"` + Params Params `json:"params" yaml:"params"` + CDPs CDPs `json:"cdps" yaml:"cdps"` + Deposits Deposits `json:"deposits" yaml:"deposits"` + StartingCdpID uint64 `json:"starting_cdp_id" yaml:"starting_cdp_id"` + DebtDenom string `json:"debt_denom" yaml:"debt_denom"` + GovDenom string `json:"gov_denom" yaml:"gov_denom"` + PreviousAccumulationTimes GenesisAccumulationTimes `json:"previous_accumulation_times" yaml:"previous_accumulation_times"` + TotalPrincipals GenesisTotalPrincipals `json:"total_principals" yaml:"total_principals"` } // NewGenesisState returns a new genesis state func NewGenesisState(params Params, cdps CDPs, deposits Deposits, startingCdpID uint64, - debtDenom, govDenom string, previousDistTime time.Time, savingsRateDist sdk.Int) GenesisState { + debtDenom, govDenom string, prevAccumTimes GenesisAccumulationTimes, + totalPrincipals GenesisTotalPrincipals) GenesisState { return GenesisState{ - Params: params, - CDPs: cdps, - Deposits: deposits, - StartingCdpID: startingCdpID, - DebtDenom: debtDenom, - GovDenom: govDenom, - PreviousDistributionTime: previousDistTime, - SavingsRateDistributed: savingsRateDist, + Params: params, + CDPs: cdps, + Deposits: deposits, + StartingCdpID: startingCdpID, + DebtDenom: debtDenom, + GovDenom: govDenom, + PreviousAccumulationTimes: prevAccumTimes, + TotalPrincipals: totalPrincipals, } } @@ -44,8 +45,8 @@ func DefaultGenesisState() GenesisState { DefaultCdpStartingID, DefaultDebtDenom, DefaultGovDenom, - DefaultPreviousDistributionTime, - DefaultSavingsRateDistributed, + GenesisAccumulationTimes{}, + GenesisTotalPrincipals{}, ) } @@ -65,11 +66,11 @@ func (gs GenesisState) Validate() error { return err } - if gs.PreviousDistributionTime.IsZero() { - return fmt.Errorf("previous distribution time not set") + if err := gs.PreviousAccumulationTimes.Validate(); err != nil { + return err } - if err := validateSavingsRateDistributed(gs.SavingsRateDistributed); err != nil { + if err := gs.TotalPrincipals.Validate(); err != nil { return err } @@ -108,3 +109,75 @@ func (gs GenesisState) Equal(gs2 GenesisState) bool { func (gs GenesisState) IsEmpty() bool { return gs.Equal(GenesisState{}) } + +// GenesisTotalPrincipal stores the total principal and its corresponding collateral type +type GenesisTotalPrincipal struct { + CollateralType string `json:"collateral_type" yaml:"collateral_type"` + TotalPrincipal sdk.Int `json:"total_principal" yaml:"total_principal"` +} + +// NewGenesisTotalPrincipal returns a new GenesisTotalPrincipal +func NewGenesisTotalPrincipal(ctype string, principal sdk.Int) GenesisTotalPrincipal { + return GenesisTotalPrincipal{ + CollateralType: ctype, + TotalPrincipal: principal, + } +} + +// GenesisTotalPrincipals slice of GenesisTotalPrincipal +type GenesisTotalPrincipals []GenesisTotalPrincipal + +// Validate performs validation of GenesisTotalPrincipal +func (gtp GenesisTotalPrincipal) Validate() error { + if gtp.TotalPrincipal.IsNegative() { + return fmt.Errorf("total principal should be positive, is %s for %s", gtp.TotalPrincipal, gtp.CollateralType) + } + return nil +} + +// Validate performs validation of GenesisTotalPrincipals +func (gtps GenesisTotalPrincipals) Validate() error { + for _, gtp := range gtps { + if err := gtp.Validate(); err != nil { + return err + } + } + return nil +} + +// GenesisAccumulationTime stores the previous distribution time and its corresponding denom +type GenesisAccumulationTime struct { + CollateralType string `json:"collateral_type" yaml:"collateral_type"` + PreviousAccumulationTime time.Time `json:"previous_accumulation_time" yaml:"previous_accumulation_time"` + InterestFactor sdk.Dec `json:"interest_factor" yaml:"interest_factor"` +} + +// NewGenesisAccumulationTime returns a new GenesisAccumulationTime +func NewGenesisAccumulationTime(ctype string, prevTime time.Time, factor sdk.Dec) GenesisAccumulationTime { + return GenesisAccumulationTime{ + CollateralType: ctype, + PreviousAccumulationTime: prevTime, + InterestFactor: factor, + } +} + +// GenesisAccumulationTimes slice of GenesisAccumulationTime +type GenesisAccumulationTimes []GenesisAccumulationTime + +// Validate performs validation of GenesisAccumulationTimes +func (gats GenesisAccumulationTimes) Validate() error { + for _, gat := range gats { + if err := gat.Validate(); err != nil { + return err + } + } + return nil +} + +// Validate performs validation of GenesisAccumulationTime +func (gat GenesisAccumulationTime) Validate() error { + if gat.InterestFactor.LT(sdk.OneDec()) { + return fmt.Errorf("interest factor should be ≥ 1.0, is %s for %s", gat.InterestFactor, gat.CollateralType) + } + return nil +} diff --git a/x/cdp/types/hooks.go b/x/cdp/types/hooks.go new file mode 100644 index 00000000..44bc732c --- /dev/null +++ b/x/cdp/types/hooks.go @@ -0,0 +1,25 @@ +package types + +import sdk "github.com/cosmos/cosmos-sdk/types" + +// MultiCDPHooks combine multiple cdp hooks, all hook functions are run in array sequence +type MultiCDPHooks []CDPHooks + +// NewMultiCDPHooks returns a new MultiCDPHooks +func NewMultiCDPHooks(hooks ...CDPHooks) MultiCDPHooks { + return hooks +} + +// BeforeCDPModified runs before a cdp is modified +func (h MultiCDPHooks) BeforeCDPModified(ctx sdk.Context, cdp CDP) { + for i := range h { + h[i].BeforeCDPModified(ctx, cdp) + } +} + +// AfterCDPCreated runs before a cdp is created +func (h MultiCDPHooks) AfterCDPCreated(ctx sdk.Context, cdp CDP) { + for i := range h { + h[i].AfterCDPCreated(ctx, cdp) + } +} diff --git a/x/cdp/types/keys.go b/x/cdp/types/keys.go index 2fe2dd82..b65d04c8 100644 --- a/x/cdp/types/keys.go +++ b/x/cdp/types/keys.go @@ -25,9 +25,6 @@ const ( // LiquidatorMacc module account for liquidator LiquidatorMacc = "liquidator" - - // SavingsRateMacc module account for savings rate - SavingsRateMacc = "savings" ) var sep = []byte(":") @@ -51,17 +48,17 @@ var sep = []byte(":") // KVStore key prefixes var ( - CdpIDKeyPrefix = []byte{0x00} - CdpKeyPrefix = []byte{0x01} - CollateralRatioIndexPrefix = []byte{0x02} - CdpIDKey = []byte{0x03} - DebtDenomKey = []byte{0x04} - GovDenomKey = []byte{0x05} - DepositKeyPrefix = []byte{0x06} - PrincipalKeyPrefix = []byte{0x07} - PreviousDistributionTimeKey = []byte{0x08} - PricefeedStatusKeyPrefix = []byte{0x09} - SavingsRateDistributedKey = []byte{0x10} + CdpIDKeyPrefix = []byte{0x01} + CdpKeyPrefix = []byte{0x02} + CollateralRatioIndexPrefix = []byte{0x03} + CdpIDKey = []byte{0x04} + DebtDenomKey = []byte{0x05} + GovDenomKey = []byte{0x06} + DepositKeyPrefix = []byte{0x07} + PrincipalKeyPrefix = []byte{0x08} + PricefeedStatusKeyPrefix = []byte{0x10} + PreviousAccrualTimePrefix = []byte{0x12} + InterestFactorPrefix = []byte{0x13} ) // GetCdpIDBytes returns the byte representation of the cdpID diff --git a/x/cdp/types/msg.go b/x/cdp/types/msg.go index ba2fe6b2..aead450d 100644 --- a/x/cdp/types/msg.go +++ b/x/cdp/types/msg.go @@ -314,3 +314,59 @@ func (msg MsgRepayDebt) String() string { Payment: %s `, msg.Sender, msg.CollateralType, msg.Payment) } + +// MsgLiquidate attempts to liquidate a borrower's cdp +type MsgLiquidate struct { + Keeper sdk.AccAddress `json:"keeper" yaml:"keeper"` + Borrower sdk.AccAddress `json:"borrower" yaml:"borrower"` + CollateralType string `json:"collateral_type" yaml:"collateral_type"` +} + +// NewMsgLiquidate returns a new MsgLiquidate +func NewMsgLiquidate(keeper, borrower sdk.AccAddress, ctype string) MsgLiquidate { + return MsgLiquidate{ + Keeper: keeper, + Borrower: borrower, + CollateralType: ctype, + } +} + +// Route return the message type used for routing the message. +func (msg MsgLiquidate) Route() string { return RouterKey } + +// Type returns a human-readable string for the message, intended for utilization within tags. +func (msg MsgLiquidate) Type() string { return "liquidate" } + +// ValidateBasic does a simple validation check that doesn't require access to any other information. +func (msg MsgLiquidate) ValidateBasic() error { + if msg.Keeper.Empty() { + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "keeper address cannot be empty") + } + if msg.Borrower.Empty() { + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "borrower address cannot be empty") + } + if strings.TrimSpace(msg.CollateralType) == "" { + return sdkerrors.Wrap(ErrInvalidCollateral, "collateral type cannot be empty") + } + return nil +} + +// GetSignBytes gets the canonical byte representation of the Msg. +func (msg MsgLiquidate) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +// GetSigners returns the addresses of signers that must sign. +func (msg MsgLiquidate) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Keeper} +} + +// String implements the Stringer interface +func (msg MsgLiquidate) String() string { + return fmt.Sprintf(`Liquidate Message: + Keeper: %s + Borrower: %s + Collateral Type %s +`, msg.Keeper, msg.Borrower, msg.CollateralType) +} diff --git a/x/cdp/types/params.go b/x/cdp/types/params.go index 58e186da..0d2598fa 100644 --- a/x/cdp/types/params.go +++ b/x/cdp/types/params.go @@ -3,64 +3,55 @@ 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" ) // Parameter keys var ( - KeyGlobalDebtLimit = []byte("GlobalDebtLimit") - KeyCollateralParams = []byte("CollateralParams") - KeyDebtParam = []byte("DebtParam") - KeyDistributionFrequency = []byte("DistributionFrequency") - KeyCircuitBreaker = []byte("CircuitBreaker") - KeyDebtThreshold = []byte("DebtThreshold") - KeyDebtLot = []byte("DebtLot") - KeySurplusThreshold = []byte("SurplusThreshold") - KeySurplusLot = []byte("SurplusLot") - KeySavingsRateDistributed = []byte("SavingsRateDistributed") - DefaultGlobalDebt = sdk.NewCoin(DefaultStableDenom, sdk.ZeroInt()) - DefaultCircuitBreaker = false - DefaultCollateralParams = CollateralParams{} - DefaultDebtParam = DebtParam{ + KeyGlobalDebtLimit = []byte("GlobalDebtLimit") + KeyCollateralParams = []byte("CollateralParams") + KeyDebtParam = []byte("DebtParam") + KeyCircuitBreaker = []byte("CircuitBreaker") + KeyDebtThreshold = []byte("DebtThreshold") + KeyDebtLot = []byte("DebtLot") + KeySurplusThreshold = []byte("SurplusThreshold") + KeySurplusLot = []byte("SurplusLot") + DefaultGlobalDebt = sdk.NewCoin(DefaultStableDenom, sdk.ZeroInt()) + DefaultCircuitBreaker = false + DefaultCollateralParams = CollateralParams{} + DefaultDebtParam = DebtParam{ Denom: "usdx", ReferenceAsset: "usd", ConversionFactor: sdk.NewInt(6), DebtFloor: sdk.NewInt(10000000), - SavingsRate: sdk.MustNewDecFromStr("0.95"), } - DefaultCdpStartingID = uint64(1) - DefaultDebtDenom = "debt" - DefaultGovDenom = "ukava" - DefaultStableDenom = "usdx" - DefaultSurplusThreshold = sdk.NewInt(500000000000) - DefaultDebtThreshold = sdk.NewInt(100000000000) - DefaultSurplusLot = sdk.NewInt(10000000000) - DefaultDebtLot = sdk.NewInt(10000000000) - DefaultPreviousDistributionTime = tmtime.Canonical(time.Unix(0, 0)) - DefaultSavingsDistributionFrequency = time.Hour * 12 - DefaultSavingsRateDistributed = sdk.NewInt(0) - minCollateralPrefix = 0 - maxCollateralPrefix = 255 - stabilityFeeMax = sdk.MustNewDecFromStr("1.000000051034942716") // 500% APR + DefaultCdpStartingID = uint64(1) + DefaultDebtDenom = "debt" + DefaultGovDenom = "ukava" + DefaultStableDenom = "usdx" + DefaultSurplusThreshold = sdk.NewInt(500000000000) + DefaultDebtThreshold = sdk.NewInt(100000000000) + DefaultSurplusLot = sdk.NewInt(10000000000) + DefaultDebtLot = sdk.NewInt(10000000000) + DefaultSavingsRateDistributed = sdk.NewInt(0) + minCollateralPrefix = 0 + maxCollateralPrefix = 255 + stabilityFeeMax = sdk.MustNewDecFromStr("1.000000051034942716") // 500% APR ) // Params governance parameters for cdp module type Params struct { - CollateralParams CollateralParams `json:"collateral_params" yaml:"collateral_params"` - DebtParam DebtParam `json:"debt_param" yaml:"debt_param"` - GlobalDebtLimit sdk.Coin `json:"global_debt_limit" yaml:"global_debt_limit"` - SurplusAuctionThreshold sdk.Int `json:"surplus_auction_threshold" yaml:"surplus_auction_threshold"` - SurplusAuctionLot sdk.Int `json:"surplus_auction_lot" yaml:"surplus_auction_lot"` - DebtAuctionThreshold sdk.Int `json:"debt_auction_threshold" yaml:"debt_auction_threshold"` - DebtAuctionLot sdk.Int `json:"debt_auction_lot" yaml:"debt_auction_lot"` - SavingsDistributionFrequency time.Duration `json:"savings_distribution_frequency" yaml:"savings_distribution_frequency"` - CircuitBreaker bool `json:"circuit_breaker" yaml:"circuit_breaker"` + CollateralParams CollateralParams `json:"collateral_params" yaml:"collateral_params"` + DebtParam DebtParam `json:"debt_param" yaml:"debt_param"` + GlobalDebtLimit sdk.Coin `json:"global_debt_limit" yaml:"global_debt_limit"` + SurplusAuctionThreshold sdk.Int `json:"surplus_auction_threshold" yaml:"surplus_auction_threshold"` + SurplusAuctionLot sdk.Int `json:"surplus_auction_lot" yaml:"surplus_auction_lot"` + DebtAuctionThreshold sdk.Int `json:"debt_auction_threshold" yaml:"debt_auction_threshold"` + DebtAuctionLot sdk.Int `json:"debt_auction_lot" yaml:"debt_auction_lot"` + CircuitBreaker bool `json:"circuit_breaker" yaml:"circuit_breaker"` } // String implements fmt.Stringer @@ -73,28 +64,26 @@ func (p Params) String() string { Surplus Auction Lot: %s Debt Auction Threshold: %s Debt Auction Lot: %s - Savings Distribution Frequency: %s Circuit Breaker: %t`, p.GlobalDebtLimit, p.CollateralParams, p.DebtParam, p.SurplusAuctionThreshold, p.SurplusAuctionLot, - p.DebtAuctionThreshold, p.DebtAuctionLot, p.SavingsDistributionFrequency, p.CircuitBreaker, + p.DebtAuctionThreshold, p.DebtAuctionLot, p.CircuitBreaker, ) } // NewParams returns a new params object func NewParams( debtLimit sdk.Coin, collateralParams CollateralParams, debtParam DebtParam, surplusThreshold, - surplusLot, debtThreshold, debtLot sdk.Int, distributionFreq time.Duration, breaker bool, + surplusLot, debtThreshold, debtLot sdk.Int, breaker bool, ) Params { return Params{ - GlobalDebtLimit: debtLimit, - CollateralParams: collateralParams, - DebtParam: debtParam, - SurplusAuctionThreshold: surplusThreshold, - SurplusAuctionLot: surplusLot, - DebtAuctionThreshold: debtThreshold, - DebtAuctionLot: debtLot, - SavingsDistributionFrequency: distributionFreq, - CircuitBreaker: breaker, + GlobalDebtLimit: debtLimit, + CollateralParams: collateralParams, + DebtParam: debtParam, + SurplusAuctionThreshold: surplusThreshold, + SurplusAuctionLot: surplusLot, + DebtAuctionThreshold: debtThreshold, + DebtAuctionLot: debtLot, + CircuitBreaker: breaker, } } @@ -102,40 +91,46 @@ func NewParams( func DefaultParams() Params { return NewParams( DefaultGlobalDebt, DefaultCollateralParams, DefaultDebtParam, DefaultSurplusThreshold, - DefaultSurplusLot, DefaultDebtThreshold, DefaultDebtLot, DefaultSavingsDistributionFrequency, + DefaultSurplusLot, DefaultDebtThreshold, DefaultDebtLot, DefaultCircuitBreaker, ) } // CollateralParam governance parameters for each collateral type within the cdp module type CollateralParam struct { - Denom string `json:"denom" yaml:"denom"` // Coin name of collateral type - Type string `json:"type" yaml:"type"` - LiquidationRatio sdk.Dec `json:"liquidation_ratio" yaml:"liquidation_ratio"` // The ratio (Collateral (priced in stable coin) / Debt) under which a CDP will be liquidated - DebtLimit sdk.Coin `json:"debt_limit" yaml:"debt_limit"` // Maximum amount of debt allowed to be drawn from this collateral type - StabilityFee sdk.Dec `json:"stability_fee" yaml:"stability_fee"` // per second stability fee for loans opened using this collateral - AuctionSize sdk.Int `json:"auction_size" yaml:"auction_size"` // Max amount of collateral to sell off in any one auction. - LiquidationPenalty sdk.Dec `json:"liquidation_penalty" yaml:"liquidation_penalty"` // percentage penalty (between [0, 1]) applied to a cdp if it is liquidated - Prefix byte `json:"prefix" yaml:"prefix"` - SpotMarketID string `json:"spot_market_id" yaml:"spot_market_id"` // marketID of the spot price of the asset from the pricefeed - used for opening CDPs, depositing, withdrawing - LiquidationMarketID string `json:"liquidation_market_id" yaml:"liquidation_market_id"` // marketID of the pricefeed used for liquidation - ConversionFactor sdk.Int `json:"conversion_factor" yaml:"conversion_factor"` // factor for converting internal units to one base unit of collateral + Denom string `json:"denom" yaml:"denom"` // Coin name of collateral type + Type string `json:"type" yaml:"type"` + LiquidationRatio sdk.Dec `json:"liquidation_ratio" yaml:"liquidation_ratio"` // The ratio (Collateral (priced in stable coin) / Debt) under which a CDP will be liquidated + DebtLimit sdk.Coin `json:"debt_limit" yaml:"debt_limit"` // Maximum amount of debt allowed to be drawn from this collateral type + StabilityFee sdk.Dec `json:"stability_fee" yaml:"stability_fee"` // per second stability fee for loans opened using this collateral + AuctionSize sdk.Int `json:"auction_size" yaml:"auction_size"` // Max amount of collateral to sell off in any one auction. + LiquidationPenalty sdk.Dec `json:"liquidation_penalty" yaml:"liquidation_penalty"` // percentage penalty (between [0, 1]) applied to a cdp if it is liquidated + Prefix byte `json:"prefix" yaml:"prefix"` + SpotMarketID string `json:"spot_market_id" yaml:"spot_market_id"` // marketID of the spot price of the asset from the pricefeed - used for opening CDPs, depositing, withdrawing + LiquidationMarketID string `json:"liquidation_market_id" yaml:"liquidation_market_id"` // marketID of the pricefeed used for liquidation + KeeperRewardPercentage sdk.Dec `json:"keeper_reward_percentage" yaml:"keeper_reward_percentage"` // the percentage of a CDPs collateral that gets rewarded to a keeper that liquidates the position + CheckCollateralizationIndexCount sdk.Int `json:"check_collateralization_index_count" yaml:"check_collateralization_index_count"` // the number of cdps that will be checked for liquidation in the begin blocker + ConversionFactor sdk.Int `json:"conversion_factor" yaml:"conversion_factor"` // factor for converting internal units to one base unit of collateral } // NewCollateralParam returns a new CollateralParam -func NewCollateralParam(denom, ctype string, liqRatio sdk.Dec, debtLimit sdk.Coin, stabilityFee sdk.Dec, auctionSize sdk.Int, liqPenalty sdk.Dec, prefix byte, spotMarketID, liquidationMarketID string, conversionFactor sdk.Int) CollateralParam { +func NewCollateralParam( + denom, ctype string, liqRatio sdk.Dec, debtLimit sdk.Coin, stabilityFee sdk.Dec, auctionSize sdk.Int, + liqPenalty sdk.Dec, prefix byte, spotMarketID, liquidationMarketID string, keeperReward sdk.Dec, checkIndexCount sdk.Int, conversionFactor sdk.Int) CollateralParam { return CollateralParam{ - Denom: denom, - Type: ctype, - LiquidationRatio: liqRatio, - DebtLimit: debtLimit, - StabilityFee: stabilityFee, - AuctionSize: auctionSize, - LiquidationPenalty: liqPenalty, - Prefix: prefix, - SpotMarketID: spotMarketID, - LiquidationMarketID: liquidationMarketID, - ConversionFactor: conversionFactor, + Denom: denom, + Type: ctype, + LiquidationRatio: liqRatio, + DebtLimit: debtLimit, + StabilityFee: stabilityFee, + AuctionSize: auctionSize, + LiquidationPenalty: liqPenalty, + Prefix: prefix, + SpotMarketID: spotMarketID, + LiquidationMarketID: liquidationMarketID, + KeeperRewardPercentage: keeperReward, + CheckCollateralizationIndexCount: checkIndexCount, + ConversionFactor: conversionFactor, } } @@ -152,8 +147,12 @@ func (cp CollateralParam) String() string { Prefix: %b Spot Market ID: %s Liquidation Market ID: %s + Keeper Reward Percentage: %s + Check Collateralization Count: %s Conversion Factor: %s`, - cp.Denom, cp.Type, cp.LiquidationRatio, cp.StabilityFee, cp.LiquidationPenalty, cp.DebtLimit, cp.AuctionSize, cp.Prefix, cp.SpotMarketID, cp.LiquidationMarketID, cp.ConversionFactor) + cp.Denom, cp.Type, cp.LiquidationRatio, cp.StabilityFee, cp.LiquidationPenalty, + cp.DebtLimit, cp.AuctionSize, cp.Prefix, cp.SpotMarketID, cp.LiquidationMarketID, + cp.KeeperRewardPercentage, cp.CheckCollateralizationIndexCount, cp.ConversionFactor) } // CollateralParams array of CollateralParam @@ -173,18 +172,16 @@ type DebtParam struct { Denom string `json:"denom" yaml:"denom"` ReferenceAsset string `json:"reference_asset" yaml:"reference_asset"` ConversionFactor sdk.Int `json:"conversion_factor" yaml:"conversion_factor"` - DebtFloor sdk.Int `json:"debt_floor" yaml:"debt_floor"` // minimum active loan size, used to prevent dust - SavingsRate sdk.Dec `json:"savings_rate" yaml:"savings_rate"` // the percentage of stability fees that are redirected to savings rate + DebtFloor sdk.Int `json:"debt_floor" yaml:"debt_floor"` // minimum active loan size, used to prevent dust } // NewDebtParam returns a new DebtParam -func NewDebtParam(denom, refAsset string, conversionFactor, debtFloor sdk.Int, savingsRate sdk.Dec) DebtParam { +func NewDebtParam(denom, refAsset string, conversionFactor, debtFloor sdk.Int) DebtParam { return DebtParam{ Denom: denom, ReferenceAsset: refAsset, ConversionFactor: conversionFactor, DebtFloor: debtFloor, - SavingsRate: savingsRate, } } @@ -194,8 +191,7 @@ func (dp DebtParam) String() string { Reference Asset: %s Conversion Factor: %s Debt Floor %s - Savings Rate %s - `, dp.Denom, dp.ReferenceAsset, dp.ConversionFactor, dp.DebtFloor, dp.SavingsRate) + `, dp.Denom, dp.ReferenceAsset, dp.ConversionFactor, dp.DebtFloor) } // DebtParams array of DebtParam @@ -228,7 +224,6 @@ func (p *Params) ParamSetPairs() params.ParamSetPairs { params.NewParamSetPair(KeySurplusLot, &p.SurplusAuctionLot, validateSurplusAuctionLotParam), params.NewParamSetPair(KeyDebtThreshold, &p.DebtAuctionThreshold, validateDebtAuctionThresholdParam), params.NewParamSetPair(KeyDebtLot, &p.DebtAuctionLot, validateDebtAuctionLotParam), - params.NewParamSetPair(KeyDistributionFrequency, &p.SavingsDistributionFrequency, validateSavingsDistributionFrequencyParam), } } @@ -266,10 +261,6 @@ func (p Params) Validate() error { return err } - if err := validateSavingsDistributionFrequencyParam(p.SavingsDistributionFrequency); err != nil { - return err - } - if len(p.CollateralParams) == 0 { // default value OK return nil } @@ -381,6 +372,12 @@ func validateCollateralParams(i interface{}) error { if cp.StabilityFee.LT(sdk.OneDec()) || cp.StabilityFee.GT(stabilityFeeMax) { return fmt.Errorf("stability fee must be ≥ 1.0, ≤ %s, is %s for %s", stabilityFeeMax, cp.StabilityFee, cp.Denom) } + if cp.KeeperRewardPercentage.IsNegative() || cp.KeeperRewardPercentage.GT(sdk.OneDec()) { + return fmt.Errorf("keeper reward percentage should be between 0 and 1, is %s for %s", cp.KeeperRewardPercentage, cp.Denom) + } + if cp.CheckCollateralizationIndexCount.IsNegative() { + return fmt.Errorf("keeper reward percentage should be positive, is %s for %s", cp.CheckCollateralizationIndexCount, cp.Denom) + } } return nil @@ -395,9 +392,6 @@ func validateDebtParam(i interface{}) error { return fmt.Errorf("debt denom invalid %s", debtParam.Denom) } - if debtParam.SavingsRate.LT(sdk.ZeroDec()) || debtParam.SavingsRate.GT(sdk.OneDec()) { - return fmt.Errorf("savings rate should be between 0 and 1, is %s for %s", debtParam.SavingsRate, debtParam.Denom) - } return nil } @@ -461,16 +455,3 @@ func validateDebtAuctionLotParam(i interface{}) error { 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 -} diff --git a/x/cdp/types/params_test.go b/x/cdp/types/params_test.go index 9e7c2c4b..17de0a82 100644 --- a/x/cdp/types/params_test.go +++ b/x/cdp/types/params_test.go @@ -3,7 +3,6 @@ package types_test import ( "strings" "testing" - "time" "github.com/stretchr/testify/suite" @@ -28,7 +27,6 @@ func (suite *ParamsTestSuite) TestParamValidation() { surplusLot sdk.Int debtThreshold sdk.Int debtLot sdk.Int - distributionFreq time.Duration breaker bool } type errArgs struct { @@ -51,7 +49,6 @@ func (suite *ParamsTestSuite) TestParamValidation() { surplusLot: types.DefaultSurplusLot, debtThreshold: types.DefaultDebtThreshold, debtLot: types.DefaultDebtLot, - distributionFreq: types.DefaultSavingsDistributionFrequency, breaker: types.DefaultCircuitBreaker, }, errArgs: errArgs{ @@ -65,17 +62,19 @@ func (suite *ParamsTestSuite) TestParamValidation() { globalDebtLimit: sdk.NewInt64Coin("usdx", 4000000000000), collateralParams: types.CollateralParams{ { - Denom: "bnb", - Type: "bnb-a", - LiquidationRatio: sdk.MustNewDecFromStr("1.5"), - DebtLimit: sdk.NewInt64Coin("usdx", 2000000000000), - StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), - LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), - AuctionSize: sdk.NewInt(50000000000), - Prefix: 0x20, - SpotMarketID: "bnb:usd", - LiquidationMarketID: "bnb:usd", - ConversionFactor: sdk.NewInt(8), + Denom: "bnb", + Type: "bnb-a", + LiquidationRatio: sdk.MustNewDecFromStr("1.5"), + DebtLimit: sdk.NewInt64Coin("usdx", 2000000000000), + StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), + LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), + AuctionSize: sdk.NewInt(50000000000), + Prefix: 0x20, + SpotMarketID: "bnb:usd", + LiquidationMarketID: "bnb:usd", + KeeperRewardPercentage: sdk.MustNewDecFromStr("0.01"), + ConversionFactor: sdk.NewInt(8), + CheckCollateralizationIndexCount: sdk.NewInt(10), }, }, debtParam: types.DebtParam{ @@ -83,13 +82,11 @@ func (suite *ParamsTestSuite) TestParamValidation() { ReferenceAsset: "usd", ConversionFactor: sdk.NewInt(6), DebtFloor: sdk.NewInt(10000000), - SavingsRate: sdk.MustNewDecFromStr("0.95"), }, surplusThreshold: types.DefaultSurplusThreshold, surplusLot: types.DefaultSurplusLot, debtThreshold: types.DefaultDebtThreshold, debtLot: types.DefaultDebtLot, - distributionFreq: types.DefaultSavingsDistributionFrequency, breaker: types.DefaultCircuitBreaker, }, errArgs: errArgs{ @@ -103,17 +100,19 @@ func (suite *ParamsTestSuite) TestParamValidation() { globalDebtLimit: sdk.NewInt64Coin("usdx", 4000000000000), collateralParams: types.CollateralParams{ { - Denom: "bnb", - Type: "bnb-a", - LiquidationRatio: sdk.MustNewDecFromStr("1.5"), - DebtLimit: sdk.NewInt64Coin("usdx", 2000000000000), - StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), - LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), - AuctionSize: sdk.NewInt(50000000000), - Prefix: 0x20, - SpotMarketID: "bnb:usd", - LiquidationMarketID: "bnb:usd", - ConversionFactor: sdk.NewInt(8), + Denom: "bnb", + Type: "bnb-a", + LiquidationRatio: sdk.MustNewDecFromStr("1.5"), + DebtLimit: sdk.NewInt64Coin("usdx", 2000000000000), + StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), + LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), + AuctionSize: sdk.NewInt(50000000000), + Prefix: 0x20, + SpotMarketID: "bnb:usd", + LiquidationMarketID: "bnb:usd", + KeeperRewardPercentage: sdk.MustNewDecFromStr("0.01"), + ConversionFactor: sdk.NewInt(8), + CheckCollateralizationIndexCount: sdk.NewInt(10), }, }, debtParam: types.DebtParam{ @@ -121,13 +120,11 @@ func (suite *ParamsTestSuite) TestParamValidation() { ReferenceAsset: "usd", ConversionFactor: sdk.NewInt(6), DebtFloor: sdk.NewInt(10000000), - SavingsRate: sdk.MustNewDecFromStr("0.95"), }, surplusThreshold: types.DefaultSurplusThreshold, surplusLot: types.DefaultSurplusLot, debtThreshold: types.DefaultDebtThreshold, debtLot: types.DefaultDebtLot, - distributionFreq: types.DefaultSavingsDistributionFrequency, breaker: types.DefaultCircuitBreaker, }, errArgs: errArgs{ @@ -141,17 +138,19 @@ func (suite *ParamsTestSuite) TestParamValidation() { globalDebtLimit: sdk.NewInt64Coin("usdx", 1000000000000), collateralParams: types.CollateralParams{ { - Denom: "bnb", - Type: "bnb-a", - LiquidationRatio: sdk.MustNewDecFromStr("1.5"), - DebtLimit: sdk.NewInt64Coin("usdx", 2000000000000), - StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), - LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), - AuctionSize: sdk.NewInt(50000000000), - Prefix: 0x20, - SpotMarketID: "bnb:usd", - LiquidationMarketID: "bnb:usd", - ConversionFactor: sdk.NewInt(8), + Denom: "bnb", + Type: "bnb-a", + LiquidationRatio: sdk.MustNewDecFromStr("1.5"), + DebtLimit: sdk.NewInt64Coin("usdx", 2000000000000), + StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), + LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), + AuctionSize: sdk.NewInt(50000000000), + Prefix: 0x20, + SpotMarketID: "bnb:usd", + LiquidationMarketID: "bnb:usd", + KeeperRewardPercentage: sdk.MustNewDecFromStr("0.01"), + ConversionFactor: sdk.NewInt(8), + CheckCollateralizationIndexCount: sdk.NewInt(10), }, }, debtParam: types.DebtParam{ @@ -159,13 +158,11 @@ func (suite *ParamsTestSuite) TestParamValidation() { ReferenceAsset: "usd", ConversionFactor: sdk.NewInt(6), DebtFloor: sdk.NewInt(10000000), - SavingsRate: sdk.MustNewDecFromStr("0.95"), }, surplusThreshold: types.DefaultSurplusThreshold, surplusLot: types.DefaultSurplusLot, debtThreshold: types.DefaultDebtThreshold, debtLot: types.DefaultDebtLot, - distributionFreq: types.DefaultSavingsDistributionFrequency, breaker: types.DefaultCircuitBreaker, }, errArgs: errArgs{ @@ -179,30 +176,34 @@ func (suite *ParamsTestSuite) TestParamValidation() { globalDebtLimit: sdk.NewInt64Coin("usdx", 4000000000000), collateralParams: types.CollateralParams{ { - Denom: "bnb", - Type: "bnb-a", - LiquidationRatio: sdk.MustNewDecFromStr("1.5"), - DebtLimit: sdk.NewInt64Coin("usdx", 2000000000000), - StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), - LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), - AuctionSize: sdk.NewInt(50000000000), - Prefix: 0x20, - SpotMarketID: "bnb:usd", - LiquidationMarketID: "bnb:usd", - ConversionFactor: sdk.NewInt(8), + Denom: "bnb", + Type: "bnb-a", + LiquidationRatio: sdk.MustNewDecFromStr("1.5"), + DebtLimit: sdk.NewInt64Coin("usdx", 2000000000000), + StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), + LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), + AuctionSize: sdk.NewInt(50000000000), + Prefix: 0x20, + SpotMarketID: "bnb:usd", + LiquidationMarketID: "bnb:usd", + KeeperRewardPercentage: sdk.MustNewDecFromStr("0.01"), + ConversionFactor: sdk.NewInt(8), + CheckCollateralizationIndexCount: sdk.NewInt(10), }, { - Denom: "xrp", - Type: "xrp-a", - LiquidationRatio: sdk.MustNewDecFromStr("1.5"), - DebtLimit: sdk.NewInt64Coin("usdx", 2000000000000), - StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), - LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), - AuctionSize: sdk.NewInt(50000000000), - Prefix: 0x21, - SpotMarketID: "xrp:usd", - LiquidationMarketID: "xrp:usd", - ConversionFactor: sdk.NewInt(6), + Denom: "xrp", + Type: "xrp-a", + LiquidationRatio: sdk.MustNewDecFromStr("1.5"), + DebtLimit: sdk.NewInt64Coin("usdx", 2000000000000), + StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), + LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), + AuctionSize: sdk.NewInt(50000000000), + Prefix: 0x21, + SpotMarketID: "xrp:usd", + LiquidationMarketID: "xrp:usd", + KeeperRewardPercentage: sdk.MustNewDecFromStr("0.01"), + ConversionFactor: sdk.NewInt(6), + CheckCollateralizationIndexCount: sdk.NewInt(10), }, }, debtParam: types.DebtParam{ @@ -210,13 +211,11 @@ func (suite *ParamsTestSuite) TestParamValidation() { ReferenceAsset: "usd", ConversionFactor: sdk.NewInt(6), DebtFloor: sdk.NewInt(10000000), - SavingsRate: sdk.MustNewDecFromStr("0.95"), }, surplusThreshold: types.DefaultSurplusThreshold, surplusLot: types.DefaultSurplusLot, debtThreshold: types.DefaultDebtThreshold, debtLot: types.DefaultDebtLot, - distributionFreq: types.DefaultSavingsDistributionFrequency, breaker: types.DefaultCircuitBreaker, }, errArgs: errArgs{ @@ -230,30 +229,34 @@ func (suite *ParamsTestSuite) TestParamValidation() { globalDebtLimit: sdk.NewInt64Coin("usdx", 2000000000000), collateralParams: types.CollateralParams{ { - Denom: "bnb", - Type: "bnb-a", - LiquidationRatio: sdk.MustNewDecFromStr("1.5"), - DebtLimit: sdk.NewInt64Coin("usdx", 2000000000000), - StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), - LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), - AuctionSize: sdk.NewInt(50000000000), - Prefix: 0x20, - SpotMarketID: "bnb:usd", - LiquidationMarketID: "bnb:usd", - ConversionFactor: sdk.NewInt(8), + Denom: "bnb", + Type: "bnb-a", + LiquidationRatio: sdk.MustNewDecFromStr("1.5"), + DebtLimit: sdk.NewInt64Coin("usdx", 2000000000000), + StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), + LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), + AuctionSize: sdk.NewInt(50000000000), + Prefix: 0x20, + SpotMarketID: "bnb:usd", + LiquidationMarketID: "bnb:usd", + KeeperRewardPercentage: sdk.MustNewDecFromStr("0.01"), + ConversionFactor: sdk.NewInt(8), + CheckCollateralizationIndexCount: sdk.NewInt(10), }, { - Denom: "xrp", - Type: "xrp-a", - LiquidationRatio: sdk.MustNewDecFromStr("1.5"), - DebtLimit: sdk.NewInt64Coin("usdx", 2000000000000), - StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), - LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), - AuctionSize: sdk.NewInt(50000000000), - Prefix: 0x21, - SpotMarketID: "xrp:usd", - LiquidationMarketID: "xrp:usd", - ConversionFactor: sdk.NewInt(6), + Denom: "xrp", + Type: "xrp-a", + LiquidationRatio: sdk.MustNewDecFromStr("1.5"), + DebtLimit: sdk.NewInt64Coin("usdx", 2000000000000), + StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), + LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), + AuctionSize: sdk.NewInt(50000000000), + Prefix: 0x21, + SpotMarketID: "xrp:usd", + LiquidationMarketID: "xrp:usd", + KeeperRewardPercentage: sdk.MustNewDecFromStr("0.01"), + ConversionFactor: sdk.NewInt(6), + CheckCollateralizationIndexCount: sdk.NewInt(10), }, }, debtParam: types.DebtParam{ @@ -261,13 +264,11 @@ func (suite *ParamsTestSuite) TestParamValidation() { ReferenceAsset: "usd", ConversionFactor: sdk.NewInt(6), DebtFloor: sdk.NewInt(10000000), - SavingsRate: sdk.MustNewDecFromStr("0.95"), }, surplusThreshold: types.DefaultSurplusThreshold, surplusLot: types.DefaultSurplusLot, debtThreshold: types.DefaultDebtThreshold, debtLot: types.DefaultDebtLot, - distributionFreq: types.DefaultSavingsDistributionFrequency, breaker: types.DefaultCircuitBreaker, }, errArgs: errArgs{ @@ -281,30 +282,34 @@ func (suite *ParamsTestSuite) TestParamValidation() { globalDebtLimit: sdk.NewInt64Coin("usdx", 4000000000000), collateralParams: types.CollateralParams{ { - Denom: "bnb", - Type: "bnb-a", - LiquidationRatio: sdk.MustNewDecFromStr("1.5"), - DebtLimit: sdk.NewInt64Coin("usdx", 2000000000000), - StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), - LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), - AuctionSize: sdk.NewInt(50000000000), - Prefix: 0x20, - SpotMarketID: "bnb:usd", - LiquidationMarketID: "bnb:usd", - ConversionFactor: sdk.NewInt(8), + Denom: "bnb", + Type: "bnb-a", + LiquidationRatio: sdk.MustNewDecFromStr("1.5"), + DebtLimit: sdk.NewInt64Coin("usdx", 2000000000000), + StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), + LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), + AuctionSize: sdk.NewInt(50000000000), + Prefix: 0x20, + SpotMarketID: "bnb:usd", + LiquidationMarketID: "bnb:usd", + KeeperRewardPercentage: sdk.MustNewDecFromStr("0.01"), + ConversionFactor: sdk.NewInt(8), + CheckCollateralizationIndexCount: sdk.NewInt(10), }, { - Denom: "xrp", - Type: "xrp-a", - LiquidationRatio: sdk.MustNewDecFromStr("1.5"), - DebtLimit: sdk.NewInt64Coin("susd", 2000000000000), - StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), - LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), - AuctionSize: sdk.NewInt(50000000000), - Prefix: 0x21, - SpotMarketID: "xrp:usd", - LiquidationMarketID: "xrp:usd", - ConversionFactor: sdk.NewInt(6), + Denom: "xrp", + Type: "xrp-a", + LiquidationRatio: sdk.MustNewDecFromStr("1.5"), + DebtLimit: sdk.NewInt64Coin("susd", 2000000000000), + StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), + LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), + AuctionSize: sdk.NewInt(50000000000), + Prefix: 0x21, + SpotMarketID: "xrp:usd", + LiquidationMarketID: "xrp:usd", + KeeperRewardPercentage: sdk.MustNewDecFromStr("0.01"), + ConversionFactor: sdk.NewInt(6), + CheckCollateralizationIndexCount: sdk.NewInt(10), }, }, debtParam: types.DebtParam{ @@ -312,13 +317,11 @@ func (suite *ParamsTestSuite) TestParamValidation() { ReferenceAsset: "usd", ConversionFactor: sdk.NewInt(6), DebtFloor: sdk.NewInt(10000000), - SavingsRate: sdk.MustNewDecFromStr("0.95"), }, surplusThreshold: types.DefaultSurplusThreshold, surplusLot: types.DefaultSurplusLot, debtThreshold: types.DefaultDebtThreshold, debtLot: types.DefaultDebtLot, - distributionFreq: types.DefaultSavingsDistributionFrequency, breaker: types.DefaultCircuitBreaker, }, errArgs: errArgs{ @@ -332,16 +335,18 @@ func (suite *ParamsTestSuite) TestParamValidation() { globalDebtLimit: sdk.NewInt64Coin("usdx", 2000000000000), collateralParams: types.CollateralParams{ { - Denom: "", - LiquidationRatio: sdk.MustNewDecFromStr("1.5"), - DebtLimit: sdk.NewInt64Coin("usdx", 2000000000000), - StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), - LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), - AuctionSize: sdk.NewInt(50000000000), - Prefix: 0x20, - SpotMarketID: "bnb:usd", - LiquidationMarketID: "bnb:usd", - ConversionFactor: sdk.NewInt(8), + Denom: "", + LiquidationRatio: sdk.MustNewDecFromStr("1.5"), + DebtLimit: sdk.NewInt64Coin("usdx", 2000000000000), + StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), + LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), + AuctionSize: sdk.NewInt(50000000000), + Prefix: 0x20, + SpotMarketID: "bnb:usd", + LiquidationMarketID: "bnb:usd", + KeeperRewardPercentage: sdk.MustNewDecFromStr("0.01"), + ConversionFactor: sdk.NewInt(8), + CheckCollateralizationIndexCount: sdk.NewInt(10), }, }, debtParam: types.DebtParam{ @@ -349,13 +354,11 @@ func (suite *ParamsTestSuite) TestParamValidation() { ReferenceAsset: "usd", ConversionFactor: sdk.NewInt(6), DebtFloor: sdk.NewInt(10000000), - SavingsRate: sdk.MustNewDecFromStr("0.95"), }, surplusThreshold: types.DefaultSurplusThreshold, surplusLot: types.DefaultSurplusLot, debtThreshold: types.DefaultDebtThreshold, debtLot: types.DefaultDebtLot, - distributionFreq: types.DefaultSavingsDistributionFrequency, breaker: types.DefaultCircuitBreaker, }, errArgs: errArgs{ @@ -369,17 +372,19 @@ func (suite *ParamsTestSuite) TestParamValidation() { globalDebtLimit: sdk.NewInt64Coin("usdx", 2000000000000), collateralParams: types.CollateralParams{ { - Denom: "bnb", - Type: "bnb-a", - LiquidationRatio: sdk.MustNewDecFromStr("1.5"), - DebtLimit: sdk.NewInt64Coin("usdx", 2000000000000), - StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), - LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), - AuctionSize: sdk.NewInt(50000000000), - Prefix: 0x20, - SpotMarketID: "", - LiquidationMarketID: "", - ConversionFactor: sdk.NewInt(8), + Denom: "bnb", + Type: "bnb-a", + LiquidationRatio: sdk.MustNewDecFromStr("1.5"), + DebtLimit: sdk.NewInt64Coin("usdx", 2000000000000), + StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), + LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), + AuctionSize: sdk.NewInt(50000000000), + Prefix: 0x20, + SpotMarketID: "", + LiquidationMarketID: "", + KeeperRewardPercentage: sdk.MustNewDecFromStr("0.01"), + ConversionFactor: sdk.NewInt(8), + CheckCollateralizationIndexCount: sdk.NewInt(10), }, }, debtParam: types.DebtParam{ @@ -387,13 +392,11 @@ func (suite *ParamsTestSuite) TestParamValidation() { ReferenceAsset: "usd", ConversionFactor: sdk.NewInt(6), DebtFloor: sdk.NewInt(10000000), - SavingsRate: sdk.MustNewDecFromStr("0.95"), }, surplusThreshold: types.DefaultSurplusThreshold, surplusLot: types.DefaultSurplusLot, debtThreshold: types.DefaultDebtThreshold, debtLot: types.DefaultDebtLot, - distributionFreq: types.DefaultSavingsDistributionFrequency, breaker: types.DefaultCircuitBreaker, }, errArgs: errArgs{ @@ -407,30 +410,34 @@ func (suite *ParamsTestSuite) TestParamValidation() { globalDebtLimit: sdk.NewInt64Coin("usdx", 2000000000000), collateralParams: types.CollateralParams{ { - Denom: "bnb", - Type: "bnb-a", - LiquidationRatio: sdk.MustNewDecFromStr("1.5"), - DebtLimit: sdk.NewInt64Coin("usdx", 1000000000000), - StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), - LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), - AuctionSize: sdk.NewInt(50000000000), - Prefix: 0x20, - SpotMarketID: "bnb:usd", - LiquidationMarketID: "bnb:usd", - ConversionFactor: sdk.NewInt(8), + Denom: "bnb", + Type: "bnb-a", + LiquidationRatio: sdk.MustNewDecFromStr("1.5"), + DebtLimit: sdk.NewInt64Coin("usdx", 1000000000000), + StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), + LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), + AuctionSize: sdk.NewInt(50000000000), + Prefix: 0x20, + SpotMarketID: "bnb:usd", + LiquidationMarketID: "bnb:usd", + KeeperRewardPercentage: sdk.MustNewDecFromStr("0.01"), + ConversionFactor: sdk.NewInt(8), + CheckCollateralizationIndexCount: sdk.NewInt(10), }, { - Denom: "bnb", - Type: "bnb-a", - LiquidationRatio: sdk.MustNewDecFromStr("1.5"), - DebtLimit: sdk.NewInt64Coin("usdx", 1000000000000), - StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), - LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), - AuctionSize: sdk.NewInt(50000000000), - Prefix: 0x21, - SpotMarketID: "bnb:usd", - LiquidationMarketID: "bnb:usd", - ConversionFactor: sdk.NewInt(8), + Denom: "bnb", + Type: "bnb-a", + LiquidationRatio: sdk.MustNewDecFromStr("1.5"), + DebtLimit: sdk.NewInt64Coin("usdx", 1000000000000), + StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), + LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), + AuctionSize: sdk.NewInt(50000000000), + Prefix: 0x21, + SpotMarketID: "bnb:usd", + LiquidationMarketID: "bnb:usd", + KeeperRewardPercentage: sdk.MustNewDecFromStr("0.01"), + ConversionFactor: sdk.NewInt(8), + CheckCollateralizationIndexCount: sdk.NewInt(10), }, }, debtParam: types.DebtParam{ @@ -438,13 +445,11 @@ func (suite *ParamsTestSuite) TestParamValidation() { ReferenceAsset: "usd", ConversionFactor: sdk.NewInt(6), DebtFloor: sdk.NewInt(10000000), - SavingsRate: sdk.MustNewDecFromStr("0.95"), }, surplusThreshold: types.DefaultSurplusThreshold, surplusLot: types.DefaultSurplusLot, debtThreshold: types.DefaultDebtThreshold, debtLot: types.DefaultDebtLot, - distributionFreq: types.DefaultSavingsDistributionFrequency, breaker: types.DefaultCircuitBreaker, }, errArgs: errArgs{ @@ -458,30 +463,34 @@ func (suite *ParamsTestSuite) TestParamValidation() { globalDebtLimit: sdk.NewInt64Coin("usdx", 2000000000000), collateralParams: types.CollateralParams{ { - Denom: "bnb", - Type: "bnb-a", - LiquidationRatio: sdk.MustNewDecFromStr("1.5"), - DebtLimit: sdk.NewInt64Coin("usdx", 1000000000000), - StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), - LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), - AuctionSize: sdk.NewInt(50000000000), - Prefix: 0x20, - SpotMarketID: "bnb:usd", - LiquidationMarketID: "bnb:usd", - ConversionFactor: sdk.NewInt(8), + Denom: "bnb", + Type: "bnb-a", + LiquidationRatio: sdk.MustNewDecFromStr("1.5"), + DebtLimit: sdk.NewInt64Coin("usdx", 1000000000000), + StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), + LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), + AuctionSize: sdk.NewInt(50000000000), + Prefix: 0x20, + SpotMarketID: "bnb:usd", + LiquidationMarketID: "bnb:usd", + KeeperRewardPercentage: sdk.MustNewDecFromStr("0.01"), + ConversionFactor: sdk.NewInt(8), + CheckCollateralizationIndexCount: sdk.NewInt(10), }, { - Denom: "bnb", - Type: "bnb-b", - LiquidationRatio: sdk.MustNewDecFromStr("1.5"), - DebtLimit: sdk.NewInt64Coin("usdx", 1000000000000), - StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), - LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), - AuctionSize: sdk.NewInt(50000000000), - Prefix: 0x21, - SpotMarketID: "bnb:usd", - LiquidationMarketID: "bnb:usd", - ConversionFactor: sdk.NewInt(8), + Denom: "bnb", + Type: "bnb-b", + LiquidationRatio: sdk.MustNewDecFromStr("1.5"), + DebtLimit: sdk.NewInt64Coin("usdx", 1000000000000), + StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), + LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), + AuctionSize: sdk.NewInt(50000000000), + Prefix: 0x21, + SpotMarketID: "bnb:usd", + LiquidationMarketID: "bnb:usd", + KeeperRewardPercentage: sdk.MustNewDecFromStr("0.01"), + ConversionFactor: sdk.NewInt(8), + CheckCollateralizationIndexCount: sdk.NewInt(10), }, }, debtParam: types.DebtParam{ @@ -489,13 +498,11 @@ func (suite *ParamsTestSuite) TestParamValidation() { ReferenceAsset: "usd", ConversionFactor: sdk.NewInt(6), DebtFloor: sdk.NewInt(10000000), - SavingsRate: sdk.MustNewDecFromStr("0.95"), }, surplusThreshold: types.DefaultSurplusThreshold, surplusLot: types.DefaultSurplusLot, debtThreshold: types.DefaultDebtThreshold, debtLot: types.DefaultDebtLot, - distributionFreq: types.DefaultSavingsDistributionFrequency, breaker: types.DefaultCircuitBreaker, }, errArgs: errArgs{ @@ -509,30 +516,34 @@ func (suite *ParamsTestSuite) TestParamValidation() { globalDebtLimit: sdk.NewInt64Coin("usdx", 2000000000000), collateralParams: types.CollateralParams{ { - Denom: "bnb", - Type: "bnb-a", - LiquidationRatio: sdk.MustNewDecFromStr("1.5"), - DebtLimit: sdk.NewInt64Coin("usdx", 1000000000000), - StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), - LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), - AuctionSize: sdk.NewInt(50000000000), - Prefix: 0x20, - SpotMarketID: "bnb:usd", - LiquidationMarketID: "bnb:usd", - ConversionFactor: sdk.NewInt(8), + Denom: "bnb", + Type: "bnb-a", + LiquidationRatio: sdk.MustNewDecFromStr("1.5"), + DebtLimit: sdk.NewInt64Coin("usdx", 1000000000000), + StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), + LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), + AuctionSize: sdk.NewInt(50000000000), + Prefix: 0x20, + SpotMarketID: "bnb:usd", + LiquidationMarketID: "bnb:usd", + KeeperRewardPercentage: sdk.MustNewDecFromStr("0.01"), + ConversionFactor: sdk.NewInt(8), + CheckCollateralizationIndexCount: sdk.NewInt(10), }, { - Denom: "xrp", - Type: "xrp-a", - LiquidationRatio: sdk.MustNewDecFromStr("1.5"), - DebtLimit: sdk.NewInt64Coin("usdx", 1000000000000), - StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), - LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), - AuctionSize: sdk.NewInt(50000000000), - Prefix: 0x20, - SpotMarketID: "xrp:usd", - LiquidationMarketID: "xrp:usd", - ConversionFactor: sdk.NewInt(8), + Denom: "xrp", + Type: "xrp-a", + LiquidationRatio: sdk.MustNewDecFromStr("1.5"), + DebtLimit: sdk.NewInt64Coin("usdx", 1000000000000), + StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), + LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), + AuctionSize: sdk.NewInt(50000000000), + Prefix: 0x20, + SpotMarketID: "xrp:usd", + LiquidationMarketID: "xrp:usd", + KeeperRewardPercentage: sdk.MustNewDecFromStr("0.01"), + ConversionFactor: sdk.NewInt(8), + CheckCollateralizationIndexCount: sdk.NewInt(10), }, }, debtParam: types.DebtParam{ @@ -540,13 +551,11 @@ func (suite *ParamsTestSuite) TestParamValidation() { ReferenceAsset: "usd", ConversionFactor: sdk.NewInt(6), DebtFloor: sdk.NewInt(10000000), - SavingsRate: sdk.MustNewDecFromStr("0.95"), }, surplusThreshold: types.DefaultSurplusThreshold, surplusLot: types.DefaultSurplusLot, debtThreshold: types.DefaultDebtThreshold, debtLot: types.DefaultDebtLot, - distributionFreq: types.DefaultSavingsDistributionFrequency, breaker: types.DefaultCircuitBreaker, }, errArgs: errArgs{ @@ -560,17 +569,19 @@ func (suite *ParamsTestSuite) TestParamValidation() { globalDebtLimit: sdk.NewInt64Coin("usdx", 2000000000000), collateralParams: types.CollateralParams{ { - Denom: "bnb", - Type: "bnb-a", - LiquidationRatio: sdk.MustNewDecFromStr("1.5"), - DebtLimit: sdk.Coin{}, - StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), - LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), - AuctionSize: sdk.NewInt(50000000000), - Prefix: 0x20, - SpotMarketID: "bnb:usd", - LiquidationMarketID: "bnb:usd", - ConversionFactor: sdk.NewInt(8), + Denom: "bnb", + Type: "bnb-a", + LiquidationRatio: sdk.MustNewDecFromStr("1.5"), + DebtLimit: sdk.Coin{}, + StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), + LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), + AuctionSize: sdk.NewInt(50000000000), + Prefix: 0x20, + SpotMarketID: "bnb:usd", + LiquidationMarketID: "bnb:usd", + KeeperRewardPercentage: sdk.MustNewDecFromStr("0.01"), + ConversionFactor: sdk.NewInt(8), + CheckCollateralizationIndexCount: sdk.NewInt(10), }, }, debtParam: types.DebtParam{ @@ -578,13 +589,11 @@ func (suite *ParamsTestSuite) TestParamValidation() { ReferenceAsset: "usd", ConversionFactor: sdk.NewInt(6), DebtFloor: sdk.NewInt(10000000), - SavingsRate: sdk.MustNewDecFromStr("0.95"), }, surplusThreshold: types.DefaultSurplusThreshold, surplusLot: types.DefaultSurplusLot, debtThreshold: types.DefaultDebtThreshold, debtLot: types.DefaultDebtLot, - distributionFreq: types.DefaultSavingsDistributionFrequency, breaker: types.DefaultCircuitBreaker, }, errArgs: errArgs{ @@ -598,17 +607,19 @@ func (suite *ParamsTestSuite) TestParamValidation() { globalDebtLimit: sdk.NewInt64Coin("usdx", 2000000000000), collateralParams: types.CollateralParams{ { - Denom: "bnb", - Type: "bnb-a", - LiquidationRatio: sdk.MustNewDecFromStr("1.5"), - DebtLimit: sdk.NewInt64Coin("usdx", 1000000000000), - StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), - LiquidationPenalty: sdk.MustNewDecFromStr("1.05"), - AuctionSize: sdk.NewInt(50000000000), - Prefix: 0x20, - SpotMarketID: "bnb:usd", - LiquidationMarketID: "bnb:usd", - ConversionFactor: sdk.NewInt(8), + Denom: "bnb", + Type: "bnb-a", + LiquidationRatio: sdk.MustNewDecFromStr("1.5"), + DebtLimit: sdk.NewInt64Coin("usdx", 1000000000000), + StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), + LiquidationPenalty: sdk.MustNewDecFromStr("1.05"), + AuctionSize: sdk.NewInt(50000000000), + Prefix: 0x20, + SpotMarketID: "bnb:usd", + LiquidationMarketID: "bnb:usd", + KeeperRewardPercentage: sdk.MustNewDecFromStr("0.01"), + ConversionFactor: sdk.NewInt(8), + CheckCollateralizationIndexCount: sdk.NewInt(10), }, }, debtParam: types.DebtParam{ @@ -616,13 +627,11 @@ func (suite *ParamsTestSuite) TestParamValidation() { ReferenceAsset: "usd", ConversionFactor: sdk.NewInt(6), DebtFloor: sdk.NewInt(10000000), - SavingsRate: sdk.MustNewDecFromStr("0.95"), }, surplusThreshold: types.DefaultSurplusThreshold, surplusLot: types.DefaultSurplusLot, debtThreshold: types.DefaultDebtThreshold, debtLot: types.DefaultDebtLot, - distributionFreq: types.DefaultSavingsDistributionFrequency, breaker: types.DefaultCircuitBreaker, }, errArgs: errArgs{ @@ -636,17 +645,19 @@ func (suite *ParamsTestSuite) TestParamValidation() { globalDebtLimit: sdk.NewInt64Coin("usdx", 2000000000000), collateralParams: types.CollateralParams{ { - Denom: "bnb", - Type: "bnb-a", - LiquidationRatio: sdk.MustNewDecFromStr("1.5"), - DebtLimit: sdk.NewInt64Coin("usdx", 1000000000000), - StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), - LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), - AuctionSize: sdk.ZeroInt(), - Prefix: 0x20, - SpotMarketID: "bnb:usd", - LiquidationMarketID: "bnb:usd", - ConversionFactor: sdk.NewInt(8), + Denom: "bnb", + Type: "bnb-a", + LiquidationRatio: sdk.MustNewDecFromStr("1.5"), + DebtLimit: sdk.NewInt64Coin("usdx", 1000000000000), + StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), + LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), + AuctionSize: sdk.ZeroInt(), + Prefix: 0x20, + SpotMarketID: "bnb:usd", + LiquidationMarketID: "bnb:usd", + KeeperRewardPercentage: sdk.MustNewDecFromStr("0.01"), + ConversionFactor: sdk.NewInt(8), + CheckCollateralizationIndexCount: sdk.NewInt(10), }, }, debtParam: types.DebtParam{ @@ -654,13 +665,11 @@ func (suite *ParamsTestSuite) TestParamValidation() { ReferenceAsset: "usd", ConversionFactor: sdk.NewInt(6), DebtFloor: sdk.NewInt(10000000), - SavingsRate: sdk.MustNewDecFromStr("0.95"), }, surplusThreshold: types.DefaultSurplusThreshold, surplusLot: types.DefaultSurplusLot, debtThreshold: types.DefaultDebtThreshold, debtLot: types.DefaultDebtLot, - distributionFreq: types.DefaultSavingsDistributionFrequency, breaker: types.DefaultCircuitBreaker, }, errArgs: errArgs{ @@ -674,17 +683,19 @@ func (suite *ParamsTestSuite) TestParamValidation() { globalDebtLimit: sdk.NewInt64Coin("usdx", 2000000000000), collateralParams: types.CollateralParams{ { - Denom: "bnb", - Type: "bnb-a", - LiquidationRatio: sdk.MustNewDecFromStr("1.5"), - DebtLimit: sdk.NewInt64Coin("usdx", 1000000000000), - StabilityFee: sdk.MustNewDecFromStr("1.1"), - LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), - AuctionSize: sdk.NewInt(50000000000), - Prefix: 0x20, - SpotMarketID: "bnb:usd", - LiquidationMarketID: "bnb:usd", - ConversionFactor: sdk.NewInt(8), + Denom: "bnb", + Type: "bnb-a", + LiquidationRatio: sdk.MustNewDecFromStr("1.5"), + DebtLimit: sdk.NewInt64Coin("usdx", 1000000000000), + StabilityFee: sdk.MustNewDecFromStr("1.1"), + LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), + AuctionSize: sdk.NewInt(50000000000), + Prefix: 0x20, + SpotMarketID: "bnb:usd", + LiquidationMarketID: "bnb:usd", + KeeperRewardPercentage: sdk.MustNewDecFromStr("0.01"), + ConversionFactor: sdk.NewInt(8), + CheckCollateralizationIndexCount: sdk.NewInt(10), }, }, debtParam: types.DebtParam{ @@ -692,13 +703,11 @@ func (suite *ParamsTestSuite) TestParamValidation() { ReferenceAsset: "usd", ConversionFactor: sdk.NewInt(6), DebtFloor: sdk.NewInt(10000000), - SavingsRate: sdk.MustNewDecFromStr("0.95"), }, surplusThreshold: types.DefaultSurplusThreshold, surplusLot: types.DefaultSurplusLot, debtThreshold: types.DefaultDebtThreshold, debtLot: types.DefaultDebtLot, - distributionFreq: types.DefaultSavingsDistributionFrequency, breaker: types.DefaultCircuitBreaker, }, errArgs: errArgs{ @@ -712,17 +721,19 @@ func (suite *ParamsTestSuite) TestParamValidation() { globalDebtLimit: sdk.NewInt64Coin("usdx", 2000000000000), collateralParams: types.CollateralParams{ { - Denom: "bnb", - Type: "bnb-a", - LiquidationRatio: sdk.MustNewDecFromStr("1.5"), - DebtLimit: sdk.NewInt64Coin("usdx", 2000000000000), - StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), - LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), - AuctionSize: sdk.NewInt(50000000000), - Prefix: 0x20, - SpotMarketID: "bnb:usd", - LiquidationMarketID: "bnb:usd", - ConversionFactor: sdk.NewInt(8), + Denom: "bnb", + Type: "bnb-a", + LiquidationRatio: sdk.MustNewDecFromStr("1.5"), + DebtLimit: sdk.NewInt64Coin("usdx", 2000000000000), + StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), + LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), + AuctionSize: sdk.NewInt(50000000000), + Prefix: 0x20, + SpotMarketID: "bnb:usd", + LiquidationMarketID: "bnb:usd", + KeeperRewardPercentage: sdk.MustNewDecFromStr("0.01"), + ConversionFactor: sdk.NewInt(8), + CheckCollateralizationIndexCount: sdk.NewInt(10), }, }, debtParam: types.DebtParam{ @@ -730,13 +741,11 @@ func (suite *ParamsTestSuite) TestParamValidation() { ReferenceAsset: "usd", ConversionFactor: sdk.NewInt(6), DebtFloor: sdk.NewInt(10000000), - SavingsRate: sdk.MustNewDecFromStr("0.95"), }, surplusThreshold: types.DefaultSurplusThreshold, surplusLot: types.DefaultSurplusLot, debtThreshold: types.DefaultDebtThreshold, debtLot: types.DefaultDebtLot, - distributionFreq: types.DefaultSavingsDistributionFrequency, breaker: types.DefaultCircuitBreaker, }, errArgs: errArgs{ @@ -744,44 +753,6 @@ func (suite *ParamsTestSuite) TestParamValidation() { contains: "debt denom invalid", }, }, - { - name: "invalid debt param savings rate out of range", - args: args{ - globalDebtLimit: sdk.NewInt64Coin("usdx", 2000000000000), - collateralParams: types.CollateralParams{ - { - Denom: "bnb", - Type: "bnb-a", - LiquidationRatio: sdk.MustNewDecFromStr("1.5"), - DebtLimit: sdk.NewInt64Coin("usdx", 2000000000000), - StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), - LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), - AuctionSize: sdk.NewInt(50000000000), - Prefix: 0x20, - SpotMarketID: "bnb:usd", - LiquidationMarketID: "bnb:usd", - ConversionFactor: sdk.NewInt(8), - }, - }, - debtParam: types.DebtParam{ - Denom: "usdx", - ReferenceAsset: "usd", - ConversionFactor: sdk.NewInt(6), - DebtFloor: sdk.NewInt(10000000), - SavingsRate: sdk.MustNewDecFromStr("1.05"), - }, - surplusThreshold: types.DefaultSurplusThreshold, - surplusLot: types.DefaultSurplusLot, - debtThreshold: types.DefaultDebtThreshold, - debtLot: types.DefaultDebtLot, - distributionFreq: types.DefaultSavingsDistributionFrequency, - breaker: types.DefaultCircuitBreaker, - }, - errArgs: errArgs{ - expectPass: false, - contains: "savings rate should be between 0 and 1", - }, - }, { name: "nil debt limit", args: args{ @@ -792,7 +763,6 @@ func (suite *ParamsTestSuite) TestParamValidation() { surplusLot: types.DefaultSurplusLot, debtThreshold: types.DefaultDebtThreshold, debtLot: types.DefaultDebtLot, - distributionFreq: types.DefaultSavingsDistributionFrequency, breaker: types.DefaultCircuitBreaker, }, errArgs: errArgs{ @@ -800,24 +770,6 @@ func (suite *ParamsTestSuite) TestParamValidation() { contains: "invalid coins: global debt limit", }, }, - { - name: "zero savings distribution frequency", - args: args{ - globalDebtLimit: types.DefaultGlobalDebt, - collateralParams: types.DefaultCollateralParams, - debtParam: types.DefaultDebtParam, - surplusThreshold: types.DefaultSurplusThreshold, - surplusLot: types.DefaultSurplusLot, - debtThreshold: types.DefaultDebtThreshold, - debtLot: types.DefaultDebtLot, - distributionFreq: time.Second * 0, - breaker: types.DefaultCircuitBreaker, - }, - errArgs: errArgs{ - expectPass: false, - contains: "savings distribution frequency should be positive", - }, - }, { name: "zero surplus auction threshold", args: args{ @@ -828,7 +780,6 @@ func (suite *ParamsTestSuite) TestParamValidation() { surplusLot: types.DefaultSurplusLot, debtThreshold: types.DefaultDebtThreshold, debtLot: types.DefaultDebtLot, - distributionFreq: types.DefaultSavingsDistributionFrequency, breaker: types.DefaultCircuitBreaker, }, errArgs: errArgs{ @@ -846,7 +797,6 @@ func (suite *ParamsTestSuite) TestParamValidation() { surplusLot: types.DefaultSurplusLot, debtThreshold: sdk.ZeroInt(), debtLot: types.DefaultDebtLot, - distributionFreq: types.DefaultSavingsDistributionFrequency, breaker: types.DefaultCircuitBreaker, }, errArgs: errArgs{ @@ -864,7 +814,6 @@ func (suite *ParamsTestSuite) TestParamValidation() { surplusLot: sdk.ZeroInt(), debtThreshold: types.DefaultDebtThreshold, debtLot: types.DefaultDebtLot, - distributionFreq: types.DefaultSavingsDistributionFrequency, breaker: types.DefaultCircuitBreaker, }, errArgs: errArgs{ @@ -882,7 +831,6 @@ func (suite *ParamsTestSuite) TestParamValidation() { surplusLot: types.DefaultSurplusLot, debtThreshold: types.DefaultDebtThreshold, debtLot: sdk.ZeroInt(), - distributionFreq: types.DefaultSavingsDistributionFrequency, breaker: types.DefaultCircuitBreaker, }, errArgs: errArgs{ @@ -893,7 +841,7 @@ func (suite *ParamsTestSuite) TestParamValidation() { } for _, tc := range testCases { suite.Run(tc.name, func() { - params := types.NewParams(tc.args.globalDebtLimit, tc.args.collateralParams, tc.args.debtParam, tc.args.surplusThreshold, tc.args.surplusLot, tc.args.debtThreshold, tc.args.debtLot, tc.args.distributionFreq, tc.args.breaker) + params := types.NewParams(tc.args.globalDebtLimit, tc.args.collateralParams, tc.args.debtParam, tc.args.surplusThreshold, tc.args.surplusLot, tc.args.debtThreshold, tc.args.debtLot, tc.args.breaker) err := params.Validate() if tc.errArgs.expectPass { suite.Require().NoError(err) diff --git a/x/committee/keeper/param_permission_test.go b/x/committee/keeper/param_permission_test.go index b2c380e3..1683bbb5 100644 --- a/x/committee/keeper/param_permission_test.go +++ b/x/committee/keeper/param_permission_test.go @@ -68,7 +68,6 @@ func (suite *PermissionTestSuite) TestSubParamChangePermission_Allows() { ReferenceAsset: "usd", ConversionFactor: i(6), DebtFloor: i(10000000), - SavingsRate: d("0.95"), } testDPUpdatedDebtFloor := testDP testDPUpdatedDebtFloor.DebtFloor = i(1000) diff --git a/x/committee/legacy/v0_11/types.go b/x/committee/legacy/v0_11/types.go index 68c1e717..e2cb58fb 100644 --- a/x/committee/legacy/v0_11/types.go +++ b/x/committee/legacy/v0_11/types.go @@ -14,7 +14,7 @@ import ( upgrade "github.com/cosmos/cosmos-sdk/x/upgrade" bep3types "github.com/kava-labs/kava/x/bep3/types" - cdptypes "github.com/kava-labs/kava/x/cdp/types" + cdptypes "github.com/kava-labs/kava/x/cdp/legacy/v0_11" "github.com/kava-labs/kava/x/pricefeed" pricefeedtypes "github.com/kava-labs/kava/x/pricefeed/types" ) diff --git a/x/committee/legacy/v0_9/types.go b/x/committee/legacy/v0_9/types.go index 43055242..483ece71 100644 --- a/x/committee/legacy/v0_9/types.go +++ b/x/committee/legacy/v0_9/types.go @@ -14,7 +14,7 @@ import ( upgrade "github.com/cosmos/cosmos-sdk/x/upgrade" bep3types "github.com/kava-labs/kava/x/bep3/types" - cdptypes "github.com/kava-labs/kava/x/cdp/types" + cdptypes "github.com/kava-labs/kava/x/cdp/legacy/v0_9" "github.com/kava-labs/kava/x/pricefeed" pricefeedtypes "github.com/kava-labs/kava/x/pricefeed/types" ) diff --git a/x/committee/types/param_permissions_test.go b/x/committee/types/param_permissions_test.go index db4dc68c..627e2b76 100644 --- a/x/committee/types/param_permissions_test.go +++ b/x/committee/types/param_permissions_test.go @@ -542,7 +542,6 @@ func (suite *PermissionsTestSuite) TestAllowedDebtParam_Allows() { ReferenceAsset: "usd", ConversionFactor: i(6), DebtFloor: i(10000000), - SavingsRate: d("0.95"), } newDenomDP := testDP newDenomDP.Denom = "usdz" @@ -564,8 +563,7 @@ func (suite *PermissionsTestSuite) TestAllowedDebtParam_Allows() { { name: "allowed change", allowed: AllowedDebtParam{ - DebtFloor: true, - SavingsRate: true, + DebtFloor: true, }, current: testDP, incoming: newDebtFloorDP, @@ -574,8 +572,7 @@ func (suite *PermissionsTestSuite) TestAllowedDebtParam_Allows() { { name: "un-allowed change", allowed: AllowedDebtParam{ - DebtFloor: true, - SavingsRate: true, + DebtFloor: true, }, current: testDP, incoming: newDenomDP, @@ -584,8 +581,7 @@ func (suite *PermissionsTestSuite) TestAllowedDebtParam_Allows() { { name: "allowed no change", allowed: AllowedDebtParam{ - DebtFloor: true, - SavingsRate: true, + DebtFloor: true, }, current: testDP, incoming: testDP, // no change @@ -594,8 +590,7 @@ func (suite *PermissionsTestSuite) TestAllowedDebtParam_Allows() { { name: "un-allowed change with allowed change", allowed: AllowedDebtParam{ - DebtFloor: true, - SavingsRate: true, + DebtFloor: true, }, current: testDP, incoming: newDenomAndDebtFloorDP, diff --git a/x/committee/types/permissions.go b/x/committee/types/permissions.go index 3b5a3921..e223b972 100644 --- a/x/committee/types/permissions.go +++ b/x/committee/types/permissions.go @@ -425,15 +425,13 @@ type AllowedDebtParam struct { ReferenceAsset bool `json:"reference_asset" yaml:"reference_asset"` ConversionFactor bool `json:"conversion_factor" yaml:"conversion_factor"` DebtFloor bool `json:"debt_floor" yaml:"debt_floor"` - SavingsRate bool `json:"savings_rate" yaml:"savings_rate"` } func (adp AllowedDebtParam) Allows(current, incoming cdptypes.DebtParam) bool { allowed := ((current.Denom == incoming.Denom) || adp.Denom) && ((current.ReferenceAsset == incoming.ReferenceAsset) || adp.ReferenceAsset) && (current.ConversionFactor.Equal(incoming.ConversionFactor) || adp.ConversionFactor) && - (current.DebtFloor.Equal(incoming.DebtFloor) || adp.DebtFloor) && - (current.SavingsRate.Equal(incoming.SavingsRate) || adp.SavingsRate) + (current.DebtFloor.Equal(incoming.DebtFloor) || adp.DebtFloor) return allowed } diff --git a/x/hard/legacy/v0_12/types.go b/x/hard/legacy/v0_11/types.go similarity index 82% rename from x/hard/legacy/v0_12/types.go rename to x/hard/legacy/v0_11/types.go index 211ced01..e1d989c6 100644 --- a/x/hard/legacy/v0_12/types.go +++ b/x/hard/legacy/v0_11/types.go @@ -1,4 +1,4 @@ -package v0_12 +package v0_11 import ( "errors" @@ -10,6 +10,22 @@ import ( "github.com/cosmos/cosmos-sdk/x/params" cdptypes "github.com/kava-labs/kava/x/cdp/types" + + tmtime "github.com/tendermint/tendermint/types/time" +) + +const ( + // ModuleName name that will be used throughout the module + ModuleName = "harvest" + + // LPAccount LP distribution module account + LPAccount = "harvest_lp_distribution" + + // DelegatorAccount delegator distribution module account + DelegatorAccount = "harvest_delegator_distribution" + + // ModuleAccountName name of module account used to hold deposits + ModuleAccountName = "harvest" ) // Parameter keys and default values @@ -21,10 +37,58 @@ var ( DefaultGovSchedules = DistributionSchedules{} DefaultLPSchedules = DistributionSchedules{} DefaultDelegatorSchedules = DelegatorDistributionSchedules{} + DefaultPreviousBlockTime = tmtime.Canonical(time.Unix(0, 0)) + DefaultDistributionTimes = GenesisDistributionTimes{} GovDenom = cdptypes.DefaultGovDenom ) -// Params governance parameters for hard module +// GenesisState is the state that must be provided at genesis. +type GenesisState struct { + Params Params `json:"params" yaml:"params"` + PreviousBlockTime time.Time `json:"previous_block_time" yaml:"previous_block_time"` + PreviousDistributionTimes GenesisDistributionTimes `json:"previous_distribution_times" yaml:"previous_distribution_times"` +} + +// NewGenesisState returns a new genesis state +func NewGenesisState(params Params, previousBlockTime time.Time, previousDistTimes GenesisDistributionTimes) GenesisState { + return GenesisState{ + Params: params, + PreviousBlockTime: previousBlockTime, + PreviousDistributionTimes: previousDistTimes, + } +} + +// Validate performs basic validation of genesis data returning an +// error for any failed validation criteria. +func (gs GenesisState) Validate() error { + + if err := gs.Params.Validate(); err != nil { + return err + } + if gs.PreviousBlockTime.Equal(time.Time{}) { + return fmt.Errorf("previous block time not set") + } + for _, gdt := range gs.PreviousDistributionTimes { + if gdt.PreviousDistributionTime.Equal(time.Time{}) { + return fmt.Errorf("previous distribution time not set for %s", gdt.Denom) + } + if err := sdk.ValidateDenom(gdt.Denom); err != nil { + return err + } + } + return nil +} + +// GenesisDistributionTime stores the previous distribution time and its corresponding denom +type GenesisDistributionTime struct { + Denom string `json:"denom" yaml:"denom"` + PreviousDistributionTime time.Time `json:"previous_distribution_time" yaml:"previous_distribution_time"` +} + +// GenesisDistributionTimes slice of GenesisDistributionTime +type GenesisDistributionTimes []GenesisDistributionTime + +// Params governance parameters for harvest module type Params struct { Active bool `json:"active" yaml:"active"` LiquidityProviderSchedules DistributionSchedules `json:"liquidity_provider_schedules" yaml:"liquidity_provider_schedules"` @@ -228,7 +292,7 @@ func NewParams(active bool, lps DistributionSchedules, dds DelegatorDistribution } } -// DefaultParams returns default params for hard module +// DefaultParams returns default params for harvest module func DefaultParams() Params { return NewParams(DefaultActive, DefaultLPSchedules, DefaultDelegatorSchedules) } @@ -342,7 +406,7 @@ func (dt DepositType) IsValid() error { return fmt.Errorf("invalid deposit type: %s", dt) } -// Deposit defines an amount of coins deposited into a hard module account +// Deposit defines an amount of coins deposited into a harvest module account type Deposit struct { Depositor sdk.AccAddress `json:"depositor" yaml:"depositor"` Amount sdk.Coin `json:"amount" yaml:"amount"` diff --git a/x/incentive/abci.go b/x/incentive/abci.go index f9786c0f..0b4b4ede 100644 --- a/x/incentive/abci.go +++ b/x/incentive/abci.go @@ -8,7 +8,10 @@ import ( // BeginBlocker runs at the start of every block func BeginBlocker(ctx sdk.Context, k keeper.Keeper) { - k.DeleteExpiredClaimsAndClaimPeriods(ctx) - k.ApplyRewardsToCdps(ctx) - k.CreateAndDeleteRewardPeriods(ctx) + for _, rp := range k.GetParams(ctx).RewardPeriods { + err := k.AccumulateRewards(ctx, rp) + if err != nil { + panic(err) + } + } } diff --git a/x/incentive/alias.go b/x/incentive/alias.go index b982477e..0c728b3b 100644 --- a/x/incentive/alias.go +++ b/x/incentive/alias.go @@ -35,77 +35,76 @@ const ( var ( // function aliases - NewKeeper = keeper.NewKeeper - NewQuerier = keeper.NewQuerier - BytesToUint64 = types.BytesToUint64 - DefaultGenesisState = types.DefaultGenesisState - DefaultParams = types.DefaultParams - GetClaimPeriodPrefix = types.GetClaimPeriodPrefix - GetClaimPrefix = types.GetClaimPrefix - GetTotalVestingPeriodLength = types.GetTotalVestingPeriodLength - NewAugmentedClaim = types.NewAugmentedClaim - NewClaim = types.NewClaim - NewClaimPeriod = types.NewClaimPeriod - NewGenesisState = types.NewGenesisState - NewMsgClaimReward = types.NewMsgClaimReward - NewMultiplier = types.NewMultiplier - NewParams = types.NewParams - NewPeriod = types.NewPeriod - NewQueryClaimsParams = types.NewQueryClaimsParams - NewReward = types.NewReward - NewRewardPeriod = types.NewRewardPeriod - NewRewardPeriodFromReward = types.NewRewardPeriodFromReward - ParamKeyTable = types.ParamKeyTable - RegisterCodec = types.RegisterCodec + CalculateTimeElapsed = keeper.CalculateTimeElapsed + NewKeeper = keeper.NewKeeper + NewQuerier = keeper.NewQuerier + DefaultGenesisState = types.DefaultGenesisState + DefaultParams = types.DefaultParams + GetTotalVestingPeriodLength = types.GetTotalVestingPeriodLength + NewGenesisAccumulationTime = types.NewGenesisAccumulationTime + NewGenesisState = types.NewGenesisState + NewMsgClaimUSDXMintingReward = types.NewMsgClaimUSDXMintingReward + NewMultiplier = types.NewMultiplier + NewParams = types.NewParams + NewPeriod = types.NewPeriod + NewQueryClaimsParams = types.NewQueryClaimsParams + NewRewardIndex = types.NewRewardIndex + NewRewardPeriod = types.NewRewardPeriod + NewUSDXMintingClaim = types.NewUSDXMintingClaim + ParamKeyTable = types.ParamKeyTable + RegisterCodec = types.RegisterCodec // variable aliases + BlockTimeKey = types.BlockTimeKey ClaimKeyPrefix = types.ClaimKeyPrefix - ClaimPeriodKeyPrefix = types.ClaimPeriodKeyPrefix DefaultActive = types.DefaultActive - DefaultPreviousBlockTime = types.DefaultPreviousBlockTime - DefaultRewards = types.DefaultRewards + DefaultClaimEnd = types.DefaultClaimEnd + DefaultClaims = types.DefaultClaims + DefaultGenesisAccumulationTimes = types.DefaultGenesisAccumulationTimes + DefaultMultipliers = types.DefaultMultipliers + DefaultRewardPeriods = types.DefaultRewardPeriods ErrAccountNotFound = types.ErrAccountNotFound + ErrClaimExpired = types.ErrClaimExpired ErrClaimNotFound = types.ErrClaimNotFound - ErrClaimPeriodNotFound = types.ErrClaimPeriodNotFound ErrInsufficientModAccountBalance = types.ErrInsufficientModAccountBalance ErrInvalidAccountType = types.ErrInvalidAccountType ErrInvalidMultiplier = types.ErrInvalidMultiplier ErrNoClaimsFound = types.ErrNoClaimsFound + ErrRewardPeriodNotFound = types.ErrRewardPeriodNotFound ErrZeroClaim = types.ErrZeroClaim GovDenom = types.GovDenom IncentiveMacc = types.IncentiveMacc KeyActive = types.KeyActive + KeyClaimEnd = types.KeyClaimEnd + KeyMultipliers = types.KeyMultipliers KeyRewards = types.KeyRewards ModuleCdc = types.ModuleCdc - NextClaimPeriodIDPrefix = types.NextClaimPeriodIDPrefix - PreviousBlockTimeKey = types.PreviousBlockTimeKey PrincipalDenom = types.PrincipalDenom - RewardPeriodKeyPrefix = types.RewardPeriodKeyPrefix + RewardFactorKey = types.RewardFactorKey + USDXMintingRewardDenom = types.USDXMintingRewardDenom ) type ( - Keeper = keeper.Keeper - AccountKeeper = types.AccountKeeper - AugmentedClaim = types.AugmentedClaim - AugmentedClaims = types.AugmentedClaims - CdpKeeper = types.CdpKeeper - Claim = types.Claim - ClaimPeriod = types.ClaimPeriod - ClaimPeriods = types.ClaimPeriods - Claims = types.Claims - GenesisClaimPeriodID = types.GenesisClaimPeriodID - GenesisClaimPeriodIDs = types.GenesisClaimPeriodIDs - GenesisState = types.GenesisState - MsgClaimReward = types.MsgClaimReward - Multiplier = types.Multiplier - MultiplierName = types.MultiplierName - Multipliers = types.Multipliers - Params = types.Params - PostClaimReq = types.PostClaimReq - QueryClaimsParams = types.QueryClaimsParams - Reward = types.Reward - RewardPeriod = types.RewardPeriod - RewardPeriods = types.RewardPeriods - Rewards = types.Rewards - SupplyKeeper = types.SupplyKeeper + Hooks = keeper.Hooks + Keeper = keeper.Keeper + AccountKeeper = types.AccountKeeper + CDPHooks = types.CDPHooks + CdpKeeper = types.CdpKeeper + GenesisAccumulationTime = types.GenesisAccumulationTime + GenesisAccumulationTimes = types.GenesisAccumulationTimes + GenesisState = types.GenesisState + MsgClaimUSDXMintingReward = types.MsgClaimUSDXMintingReward + Multiplier = types.Multiplier + MultiplierName = types.MultiplierName + Multipliers = types.Multipliers + Params = types.Params + PostClaimReq = types.PostClaimReq + QueryClaimsParams = types.QueryClaimsParams + RewardIndex = types.RewardIndex + RewardIndexes = types.RewardIndexes + RewardPeriod = types.RewardPeriod + RewardPeriods = types.RewardPeriods + SupplyKeeper = types.SupplyKeeper + USDXMintingClaim = types.USDXMintingClaim + USDXMintingClaims = types.USDXMintingClaims ) diff --git a/x/incentive/client/cli/query.go b/x/incentive/client/cli/query.go index e3dc4bf7..fd600a15 100644 --- a/x/incentive/client/cli/query.go +++ b/x/incentive/client/cli/query.go @@ -5,6 +5,7 @@ import ( "strings" "github.com/spf13/cobra" + "github.com/spf13/viper" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/flags" @@ -25,35 +26,42 @@ func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { incentiveQueryCmd.AddCommand(flags.GetCommands( queryParamsCmd(queryRoute, cdc), queryClaimsCmd(queryRoute, cdc), - queryRewardPeriodsCmd(queryRoute, cdc), - queryClaimPeriodsCmd(queryRoute, cdc), )...) return incentiveQueryCmd - } +const ( + flagOwner = "owner" +) + func queryClaimsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "claims [owner-addr] [collateral-type]", - Short: "get claims by owner and collateral-type", + cmd := &cobra.Command{ + Use: "claims ", + Short: "query USDX minting claims", Long: strings.TrimSpace( - fmt.Sprintf(`Get all claims owned by the owner address for the particular collateral type. + fmt.Sprintf(`Query USDX minting claims with optional flag for finding claims for a specifc owner Example: - $ %s query %s claims kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw bnb-a`, version.ClientName, types.ModuleName)), - Args: cobra.ExactArgs(2), + $ %s query %s claims + $ %s query %s claims --owner kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw + `, + version.ClientName, types.ModuleName, version.ClientName, types.ModuleName)), + Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { cliCtx := context.NewCLIContext().WithCodec(cdc) + + strOwner := viper.GetString(flagOwner) + page := viper.GetInt(flags.FlagPage) + limit := viper.GetInt(flags.FlagLimit) + // Prepare params for querier - ownerAddress, err := sdk.AccAddressFromBech32(args[0]) + owner, err := sdk.AccAddressFromBech32(strOwner) if err != nil { return err } - bz, err := cdc.MarshalJSON(types.QueryClaimsParams{ - Owner: ownerAddress, - CollateralType: args[1], - }) + params := types.NewQueryClaimsParams(page, limit, owner) + bz, err := cdc.MarshalJSON(params) if err != nil { return err } @@ -66,7 +74,7 @@ func queryClaimsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { } cliCtx = cliCtx.WithHeight(height) - var claims types.AugmentedClaims + var claims types.USDXMintingClaims if err := cdc.UnmarshalJSON(res, &claims); err != nil { return fmt.Errorf("failed to unmarshal claims: %w", err) } @@ -74,6 +82,10 @@ func queryClaimsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { }, } + cmd.Flags().String(flagOwner, "", "(optional) filter by claim owner address") + cmd.Flags().Int(flags.FlagPage, 1, "pagination page of CDPs to to query for") + cmd.Flags().Int(flags.FlagLimit, 100, "pagination limit of CDPs to query for") + return cmd } func queryParamsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { @@ -102,57 +114,3 @@ func queryParamsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { }, } } - -func queryRewardPeriodsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "reward-periods", - Short: "get active reward periods", - Long: "Get the current set of active incentive reward periods.", - Args: cobra.NoArgs, - RunE: func(cmd *cobra.Command, args []string) error { - cliCtx := context.NewCLIContext().WithCodec(cdc) - - // Query - route := fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryGetRewardPeriods) - res, height, err := cliCtx.QueryWithData(route, nil) - if err != nil { - return err - } - cliCtx = cliCtx.WithHeight(height) - - // Decode and print results - var rewardPeriods types.RewardPeriods - if err := cdc.UnmarshalJSON(res, &rewardPeriods); err != nil { - return fmt.Errorf("failed to unmarshal reward periods: %w", err) - } - return cliCtx.PrintOutput(rewardPeriods) - }, - } -} - -func queryClaimPeriodsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "claim-periods", - Short: "get active claim periods", - Long: "Get the current set of active incentive claim periods.", - Args: cobra.NoArgs, - RunE: func(cmd *cobra.Command, args []string) error { - cliCtx := context.NewCLIContext().WithCodec(cdc) - - // Query - route := fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryGetClaimPeriods) - res, height, err := cliCtx.QueryWithData(route, nil) - if err != nil { - return err - } - cliCtx = cliCtx.WithHeight(height) - - // Decode and print results - var claimPeriods types.ClaimPeriods - if err := cdc.UnmarshalJSON(res, &claimPeriods); err != nil { - return fmt.Errorf("failed to unmarshal claim periods: %w", err) - } - return cliCtx.PrintOutput(claimPeriods) - }, - } -} diff --git a/x/incentive/client/cli/tx.go b/x/incentive/client/cli/tx.go index 91fa9a0e..5a51ea4a 100644 --- a/x/incentive/client/cli/tx.go +++ b/x/incentive/client/cli/tx.go @@ -35,16 +35,16 @@ func GetTxCmd(cdc *codec.Codec) *cobra.Command { func getCmdClaim(cdc *codec.Codec) *cobra.Command { return &cobra.Command{ - Use: "claim [owner] [collateral-type] [multiplier]", + Use: "claim [owner] [multiplier]", Short: "claim rewards for cdp owner and collateral-type", Long: strings.TrimSpace( fmt.Sprintf(`Claim any outstanding rewards owned by owner for the input collateral-type and multiplier, Example: - $ %s tx %s claim kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw bnb-a large + $ %s tx %s claim kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw large `, version.ClientName, types.ModuleName), ), - Args: cobra.ExactArgs(3), + Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { inBuf := bufio.NewReader(cmd.InOrStdin()) cliCtx := context.NewCLIContextWithInputAndFrom(inBuf, args[0]).WithCodec(cdc) @@ -54,7 +54,7 @@ func getCmdClaim(cdc *codec.Codec) *cobra.Command { return err } - msg := types.NewMsgClaimReward(owner, args[1], args[2]) + msg := types.NewMsgClaimUSDXMintingReward(owner, args[1]) err = msg.ValidateBasic() if err != nil { return err diff --git a/x/incentive/client/rest/query.go b/x/incentive/client/rest/query.go index 429c97b0..09d14072 100644 --- a/x/incentive/client/rest/query.go +++ b/x/incentive/client/rest/query.go @@ -3,6 +3,7 @@ package rest import ( "fmt" "net/http" + "strings" "github.com/gorilla/mux" @@ -14,30 +15,33 @@ import ( ) func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router) { - r.HandleFunc(fmt.Sprintf("/%s/claims/{%s}/{%s}", types.ModuleName, types.RestClaimOwner, types.RestClaimCollateralType), queryClaimsHandlerFn(cliCtx)).Methods("GET") - r.HandleFunc(fmt.Sprintf("/%s/rewardperiods", types.ModuleName), queryRewardPeriodsHandlerFn(cliCtx)).Methods("GET") - r.HandleFunc(fmt.Sprintf("/%s/claimperiods", types.ModuleName), queryClaimPeriodsHandlerFn(cliCtx)).Methods("GET") + r.HandleFunc(fmt.Sprintf("/%s/claims", types.ModuleName), queryClaimsHandlerFn(cliCtx)).Methods("GET") r.HandleFunc(fmt.Sprintf("/%s/parameters", types.ModuleName), queryParamsHandlerFn(cliCtx)).Methods("GET") } func queryClaimsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { + _, page, limit, err := rest.ParseHTTPArgsWithLimit(r, 0) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) if !ok { return } - vars := mux.Vars(r) - ownerBech32 := vars[types.RestClaimOwner] - denom := vars[types.RestClaimCollateralType] - - owner, err := sdk.AccAddressFromBech32(ownerBech32) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) - return + var owner sdk.AccAddress + if x := r.URL.Query().Get(types.RestClaimOwner); len(x) != 0 { + ownerStr := strings.ToLower(strings.TrimSpace(x)) + owner, err = sdk.AccAddressFromBech32(ownerStr) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("cannot parse address from claim owner %s", ownerStr)) + return + } } - queryParams := types.NewQueryClaimsParams(owner, denom) + queryParams := types.NewQueryClaimsParams(page, limit, owner) bz, err := cliCtx.Codec.MarshalJSON(queryParams) if err != nil { rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to marshal query params: %s", err)) @@ -55,46 +59,6 @@ func queryClaimsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { } } -func queryRewardPeriodsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) - if !ok { - return - } - - route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryGetRewardPeriods) - - res, height, err := cliCtx.QueryWithData(route, nil) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) - return - } - - cliCtx = cliCtx.WithHeight(height) - rest.PostProcessResponse(w, cliCtx, res) - } -} - -func queryClaimPeriodsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) - if !ok { - return - } - - route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryGetClaimPeriods) - - res, height, err := cliCtx.QueryWithData(route, nil) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) - return - } - - cliCtx = cliCtx.WithHeight(height) - rest.PostProcessResponse(w, cliCtx, res) - } -} - func queryParamsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) diff --git a/x/incentive/client/rest/tx.go b/x/incentive/client/rest/tx.go index 2e19070c..ef4745fd 100644 --- a/x/incentive/client/rest/tx.go +++ b/x/incentive/client/rest/tx.go @@ -42,7 +42,7 @@ func postClaimHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return } - msg := types.NewMsgClaimReward(requestBody.Sender, requestBody.CollateralType, requestBody.MultiplierName) + msg := types.NewMsgClaimUSDXMintingReward(requestBody.Sender, requestBody.MultiplierName) if err := msg.ValidateBasic(); err != nil { rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return diff --git a/x/incentive/genesis.go b/x/incentive/genesis.go index cda9c07c..91bb905c 100644 --- a/x/incentive/genesis.go +++ b/x/incentive/genesis.go @@ -24,51 +24,37 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, supplyKeeper types.SupplyKeep k.SetParams(ctx, gs.Params) - for _, r := range gs.Params.Rewards { - k.SetNextClaimPeriodID(ctx, r.CollateralType, 1) + for _, gat := range gs.PreviousAccumulationTimes { + k.SetPreviousAccrualTime(ctx, gat.CollateralType, gat.PreviousAccumulationTime) + k.SetRewardFactor(ctx, gat.CollateralType, gat.RewardFactor) } - // only set the previous block time if it's different than default - if !gs.PreviousBlockTime.Equal(types.DefaultPreviousBlockTime) { - k.SetPreviousBlockTime(ctx, gs.PreviousBlockTime) - } - - // set store objects - for _, rp := range gs.RewardPeriods { - k.SetRewardPeriod(ctx, rp) - } - - for _, cp := range gs.ClaimPeriods { - k.SetClaimPeriod(ctx, cp) - } - - for _, c := range gs.Claims { - k.SetClaim(ctx, c) - } - - for _, id := range gs.NextClaimPeriodIDs { - k.SetNextClaimPeriodID(ctx, id.CollateralType, id.ID) + for _, claim := range gs.USDXMintingClaims { + k.SetClaim(ctx, claim) } } // ExportGenesis export genesis state for incentive module func ExportGenesis(ctx sdk.Context, k keeper.Keeper) types.GenesisState { - // get all objects out of the store params := k.GetParams(ctx) - previousBlockTime, found := k.GetPreviousBlockTime(ctx) - // since it is not set in genesis, if somehow the chain got started and was exported - // immediately after InitGenesis, there would be no previousBlockTime value. - if !found { - previousBlockTime = types.DefaultPreviousBlockTime + claims := k.GetAllClaims(ctx) + + var gats GenesisAccumulationTimes + + for _, rp := range params.RewardPeriods { + pat, found := k.GetPreviousAccrualTime(ctx, rp.CollateralType) + if !found { + pat = ctx.BlockTime() + } + factor, found := k.GetRewardFactor(ctx, rp.CollateralType) + if !found { + factor = sdk.ZeroDec() + } + gat := types.NewGenesisAccumulationTime(rp.CollateralType, pat, factor) + gats = append(gats, gat) } - // Get all objects from the store - rewardPeriods := k.GetAllRewardPeriods(ctx) - claimPeriods := k.GetAllClaimPeriods(ctx) - claims := k.GetAllClaims(ctx) - claimPeriodIDs := k.GetAllClaimPeriodIDPairs(ctx) - - return types.NewGenesisState(params, previousBlockTime, rewardPeriods, claimPeriods, claims, claimPeriodIDs) + return types.NewGenesisState(params, gats, claims) } diff --git a/x/incentive/handler.go b/x/incentive/handler.go index 7d6f5fc8..ef2b2344 100644 --- a/x/incentive/handler.go +++ b/x/incentive/handler.go @@ -1,8 +1,6 @@ package incentive import ( - "strings" - sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -15,36 +13,20 @@ func NewHandler(k keeper.Keeper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { ctx = ctx.WithEventManager(sdk.NewEventManager()) switch msg := msg.(type) { - case types.MsgClaimReward: - return handleMsgClaimReward(ctx, k, msg) + case types.MsgClaimUSDXMintingReward: + return handleMsgClaimUSDXMintingReward(ctx, k, msg) default: return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", ModuleName, msg) - } } } -func handleMsgClaimReward(ctx sdk.Context, k keeper.Keeper, msg types.MsgClaimReward) (*sdk.Result, error) { +func handleMsgClaimUSDXMintingReward(ctx sdk.Context, k keeper.Keeper, msg types.MsgClaimUSDXMintingReward) (*sdk.Result, error) { - claims, found := k.GetActiveClaimsByAddressAndCollateralType(ctx, msg.Sender, msg.CollateralType) - if !found { - return nil, sdkerrors.Wrapf(types.ErrNoClaimsFound, "address: %s, collateral type: %s", msg.Sender, msg.CollateralType) + err := k.ClaimReward(ctx, msg.Sender, types.MultiplierName(msg.MultiplierName)) + if err != nil { + return nil, err } - - for _, claim := range claims { - err := k.PayoutClaim(ctx, claim.Owner, claim.CollateralType, claim.ClaimPeriodID, types.MultiplierName(strings.ToLower(msg.MultiplierName))) - if err != nil { - return nil, err - } - } - ctx.EventManager().EmitEvent( - sdk.NewEvent( - sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), - sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender.String()), - ), - ) - return &sdk.Result{ Events: ctx.EventManager().Events(), }, nil diff --git a/x/incentive/handler_test.go b/x/incentive/handler_test.go index 4aa7b376..4f872099 100644 --- a/x/incentive/handler_test.go +++ b/x/incentive/handler_test.go @@ -13,6 +13,7 @@ import ( "github.com/kava-labs/kava/app" "github.com/kava-labs/kava/x/incentive" + "github.com/kava-labs/kava/x/incentive/types" "github.com/kava-labs/kava/x/kavadist" ) @@ -41,7 +42,16 @@ func (suite *HandlerTestSuite) SetupTest() { coins = append(coins, cs(c("bnb", 10000000000), c("ukava", 10000000000))) } authGS := app.NewAuthGenState(addrs, coins) - tApp.InitializeFromGenesisStates(authGS) + incentiveGS := incentive.NewGenesisState( + incentive.NewParams( + incentive.RewardPeriods{incentive.NewRewardPeriod(true, "bnb-a", time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), time.Date(2024, 12, 15, 14, 0, 0, 0, time.UTC), c("ukava", 122354))}, + incentive.Multipliers{incentive.NewMultiplier(incentive.MultiplierName("small"), 1, d("0.25")), incentive.NewMultiplier(incentive.MultiplierName("large"), 12, d("1.0"))}, + time.Date(2025, 12, 15, 14, 0, 0, 0, time.UTC), + ), + incentive.DefaultGenesisAccumulationTimes, + incentive.DefaultClaims, + ) + tApp.InitializeFromGenesisStates(authGS, app.GenesisState{incentive.ModuleName: incentive.ModuleCdc.MustMarshalJSON(incentiveGS)}) suite.addrs = addrs suite.handler = incentive.NewHandler(keeper) @@ -51,15 +61,10 @@ func (suite *HandlerTestSuite) SetupTest() { } func (suite *HandlerTestSuite) addClaim() { - supplyKeeper := suite.app.GetSupplyKeeper() - macc := supplyKeeper.GetModuleAccount(suite.ctx, kavadist.ModuleName) - err := supplyKeeper.MintCoins(suite.ctx, macc.GetName(), cs(c("ukava", 1000000))) + sk := suite.app.GetSupplyKeeper() + err := sk.MintCoins(suite.ctx, kavadist.ModuleName, cs(c("ukava", 1000000000000))) suite.Require().NoError(err) - cp := incentive.NewClaimPeriod("bnb", 1, suite.ctx.BlockTime().Add(time.Hour*168), incentive.Multipliers{incentive.NewMultiplier(incentive.Small, 1, sdk.MustNewDecFromStr("0.33"))}) - suite.NotPanics(func() { - suite.keeper.SetClaimPeriod(suite.ctx, cp) - }) - c1 := incentive.NewClaim(suite.addrs[0], c("ukava", 1000000), "bnb", 1) + c1 := incentive.NewUSDXMintingClaim(suite.addrs[0], c("ukava", 1000000), types.RewardIndexes{types.NewRewardIndex("bnb-s", sdk.ZeroDec())}) suite.NotPanics(func() { suite.keeper.SetClaim(suite.ctx, c1) }) @@ -67,7 +72,7 @@ func (suite *HandlerTestSuite) addClaim() { func (suite *HandlerTestSuite) TestMsgClaimReward() { suite.addClaim() - msg := incentive.NewMsgClaimReward(suite.addrs[0], "bnb", "small") + msg := incentive.NewMsgClaimUSDXMintingReward(suite.addrs[0], "small") res, err := suite.handler(suite.ctx, msg) suite.NoError(err) suite.Require().NotNil(res) @@ -75,3 +80,7 @@ func (suite *HandlerTestSuite) TestMsgClaimReward() { func TestHandlerTestSuite(t *testing.T) { suite.Run(t, new(HandlerTestSuite)) } + +// Avoid cluttering test cases with long function names +func i(in int64) sdk.Int { return sdk.NewInt(in) } +func d(str string) sdk.Dec { return sdk.MustNewDecFromStr(str) } diff --git a/x/incentive/keeper/hooks.go b/x/incentive/keeper/hooks.go new file mode 100644 index 00000000..0482dd5e --- /dev/null +++ b/x/incentive/keeper/hooks.go @@ -0,0 +1,28 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + cdptypes "github.com/kava-labs/kava/x/cdp/types" +) + +// Hooks wrapper struct for hooks +type Hooks struct { + k Keeper +} + +var _ cdptypes.CDPHooks = Hooks{} + +// Hooks create new incentive hooks +func (k Keeper) Hooks() Hooks { return Hooks{k} } + +// AfterCDPCreated function that runs after a cdp is created +func (h Hooks) AfterCDPCreated(ctx sdk.Context, cdp cdptypes.CDP) { + h.k.InitializeClaim(ctx, cdp) +} + +// BeforeCDPModified function that runs before a cdp is modified +// note that this is called immediately after interest is synchronized, and so could potentially +// be called AfterCDPInterestUpdated or something like that, if we we're to expand the scope of cdp hooks +func (h Hooks) BeforeCDPModified(ctx sdk.Context, cdp cdptypes.CDP) { + h.k.SynchronizeReward(ctx, cdp) +} diff --git a/x/incentive/keeper/integration_test.go b/x/incentive/keeper/integration_test.go new file mode 100644 index 00000000..cdc3f774 --- /dev/null +++ b/x/incentive/keeper/integration_test.go @@ -0,0 +1,212 @@ +package keeper_test + +import ( + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/kava-labs/kava/app" + "github.com/kava-labs/kava/x/cdp" + "github.com/kava-labs/kava/x/incentive" + "github.com/kava-labs/kava/x/pricefeed" +) + +func NewCDPGenStateMulti() app.GenesisState { + cdpGenesis := cdp.GenesisState{ + Params: cdp.Params{ + GlobalDebtLimit: sdk.NewInt64Coin("usdx", 2000000000000), + SurplusAuctionThreshold: cdp.DefaultSurplusThreshold, + SurplusAuctionLot: cdp.DefaultSurplusLot, + DebtAuctionThreshold: cdp.DefaultDebtThreshold, + DebtAuctionLot: cdp.DefaultDebtLot, + CollateralParams: cdp.CollateralParams{ + { + Denom: "xrp", + Type: "xrp-a", + LiquidationRatio: sdk.MustNewDecFromStr("2.0"), + DebtLimit: sdk.NewInt64Coin("usdx", 500000000000), + StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), // %5 apr + LiquidationPenalty: d("0.05"), + AuctionSize: i(7000000000), + Prefix: 0x20, + SpotMarketID: "xrp:usd", + LiquidationMarketID: "xrp:usd", + ConversionFactor: i(6), + }, + { + Denom: "btc", + Type: "btc-a", + LiquidationRatio: sdk.MustNewDecFromStr("1.5"), + DebtLimit: sdk.NewInt64Coin("usdx", 500000000000), + StabilityFee: sdk.MustNewDecFromStr("1.000000000782997609"), // %2.5 apr + LiquidationPenalty: d("0.025"), + AuctionSize: i(10000000), + Prefix: 0x21, + SpotMarketID: "btc:usd", + LiquidationMarketID: "btc:usd", + ConversionFactor: i(8), + }, + { + Denom: "bnb", + Type: "bnb-a", + LiquidationRatio: sdk.MustNewDecFromStr("1.5"), + DebtLimit: sdk.NewInt64Coin("usdx", 500000000000), + StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), // %5 apr + LiquidationPenalty: d("0.05"), + AuctionSize: i(50000000000), + Prefix: 0x22, + SpotMarketID: "bnb:usd", + LiquidationMarketID: "bnb:usd", + ConversionFactor: i(8), + }, + { + Denom: "busd", + Type: "busd-a", + LiquidationRatio: d("1.01"), + DebtLimit: sdk.NewInt64Coin("usdx", 500000000000), + StabilityFee: sdk.OneDec(), // %0 apr + LiquidationPenalty: d("0.05"), + AuctionSize: i(10000000000), + Prefix: 0x23, + SpotMarketID: "busd:usd", + LiquidationMarketID: "busd:usd", + ConversionFactor: i(8), + }, + }, + DebtParam: cdp.DebtParam{ + Denom: "usdx", + ReferenceAsset: "usd", + ConversionFactor: i(6), + DebtFloor: i(10000000), + }, + }, + StartingCdpID: cdp.DefaultCdpStartingID, + DebtDenom: cdp.DefaultDebtDenom, + GovDenom: cdp.DefaultGovDenom, + CDPs: cdp.CDPs{}, + PreviousAccumulationTimes: cdp.GenesisAccumulationTimes{ + cdp.NewGenesisAccumulationTime("btc-a", time.Time{}, sdk.OneDec()), + cdp.NewGenesisAccumulationTime("xrp-a", time.Time{}, sdk.OneDec()), + cdp.NewGenesisAccumulationTime("busd-a", time.Time{}, sdk.OneDec()), + cdp.NewGenesisAccumulationTime("bnb-a", time.Time{}, sdk.OneDec()), + }, + TotalPrincipals: cdp.GenesisTotalPrincipals{ + cdp.NewGenesisTotalPrincipal("btc-a", sdk.ZeroInt()), + cdp.NewGenesisTotalPrincipal("xrp-a", sdk.ZeroInt()), + cdp.NewGenesisTotalPrincipal("busd-a", sdk.ZeroInt()), + cdp.NewGenesisTotalPrincipal("bnb-a", sdk.ZeroInt()), + }, + } + return app.GenesisState{cdp.ModuleName: cdp.ModuleCdc.MustMarshalJSON(cdpGenesis)} +} + +func NewPricefeedGenStateMulti() app.GenesisState { + pfGenesis := pricefeed.GenesisState{ + Params: pricefeed.Params{ + Markets: []pricefeed.Market{ + {MarketID: "btc:usd", BaseAsset: "btc", QuoteAsset: "usd", Oracles: []sdk.AccAddress{}, Active: true}, + {MarketID: "xrp:usd", BaseAsset: "xrp", QuoteAsset: "usd", Oracles: []sdk.AccAddress{}, Active: true}, + {MarketID: "bnb:usd", BaseAsset: "bnb", QuoteAsset: "usd", Oracles: []sdk.AccAddress{}, Active: true}, + {MarketID: "busd:usd", BaseAsset: "busd", QuoteAsset: "usd", Oracles: []sdk.AccAddress{}, Active: true}, + }, + }, + PostedPrices: []pricefeed.PostedPrice{ + { + MarketID: "btc:usd", + OracleAddress: sdk.AccAddress{}, + Price: sdk.MustNewDecFromStr("8000.00"), + Expiry: time.Now().Add(1 * time.Hour), + }, + { + MarketID: "xrp:usd", + OracleAddress: sdk.AccAddress{}, + Price: sdk.MustNewDecFromStr("0.25"), + Expiry: time.Now().Add(1 * time.Hour), + }, + { + MarketID: "bnb:usd", + OracleAddress: sdk.AccAddress{}, + Price: sdk.MustNewDecFromStr("17.25"), + Expiry: time.Now().Add(1 * time.Hour), + }, + { + MarketID: "busd:usd", + OracleAddress: sdk.AccAddress{}, + Price: sdk.OneDec(), + Expiry: time.Now().Add(1 * time.Hour), + }, + }, + } + return app.GenesisState{pricefeed.ModuleName: pricefeed.ModuleCdc.MustMarshalJSON(pfGenesis)} +} + +func NewIncentiveGenState(previousAccumTime, endTime time.Time, rewardPeriods ...incentive.RewardPeriod) app.GenesisState { + var accumulationTimes incentive.GenesisAccumulationTimes + for _, rp := range rewardPeriods { + accumulationTimes = append( + accumulationTimes, + incentive.NewGenesisAccumulationTime( + rp.CollateralType, + previousAccumTime, + sdk.ZeroDec(), + ), + ) + } + genesis := incentive.NewGenesisState( + incentive.NewParams( + rewardPeriods, + incentive.Multipliers{ + incentive.NewMultiplier(incentive.Small, 1, d("0.25")), + incentive.NewMultiplier(incentive.Large, 12, d("1.0")), + }, + endTime, + ), + accumulationTimes, + incentive.USDXMintingClaims{}, + ) + return app.GenesisState{incentive.ModuleName: incentive.ModuleCdc.MustMarshalJSON(genesis)} +} + +func NewCDPGenStateHighInterest() app.GenesisState { + cdpGenesis := cdp.GenesisState{ + Params: cdp.Params{ + GlobalDebtLimit: sdk.NewInt64Coin("usdx", 2000000000000), + SurplusAuctionThreshold: cdp.DefaultSurplusThreshold, + SurplusAuctionLot: cdp.DefaultSurplusLot, + DebtAuctionThreshold: cdp.DefaultDebtThreshold, + DebtAuctionLot: cdp.DefaultDebtLot, + CollateralParams: cdp.CollateralParams{ + { + Denom: "bnb", + Type: "bnb-a", + LiquidationRatio: sdk.MustNewDecFromStr("1.5"), + DebtLimit: sdk.NewInt64Coin("usdx", 500000000000), + StabilityFee: sdk.MustNewDecFromStr("1.000000051034942716"), // 500% APR + LiquidationPenalty: d("0.05"), + AuctionSize: i(50000000000), + Prefix: 0x22, + SpotMarketID: "bnb:usd", + LiquidationMarketID: "bnb:usd", + ConversionFactor: i(8), + }, + }, + DebtParam: cdp.DebtParam{ + Denom: "usdx", + ReferenceAsset: "usd", + ConversionFactor: i(6), + DebtFloor: i(10000000), + }, + }, + StartingCdpID: cdp.DefaultCdpStartingID, + DebtDenom: cdp.DefaultDebtDenom, + GovDenom: cdp.DefaultGovDenom, + CDPs: cdp.CDPs{}, + PreviousAccumulationTimes: cdp.GenesisAccumulationTimes{ + cdp.NewGenesisAccumulationTime("bnb-a", time.Time{}, sdk.OneDec()), + }, + TotalPrincipals: cdp.GenesisTotalPrincipals{ + cdp.NewGenesisTotalPrincipal("bnb-a", sdk.ZeroInt()), + }, + } + return app.GenesisState{cdp.ModuleName: cdp.ModuleCdc.MustMarshalJSON(cdpGenesis)} +} diff --git a/x/incentive/keeper/keeper.go b/x/incentive/keeper/keeper.go index 855f6080..3a2f4020 100644 --- a/x/incentive/keeper/keeper.go +++ b/x/incentive/keeper/keeper.go @@ -37,182 +37,39 @@ func NewKeeper( } } -// GetRewardPeriod returns the reward period from the store for the input collateral type and a boolean for if it was found -func (k Keeper) GetRewardPeriod(ctx sdk.Context, collateralType string) (types.RewardPeriod, bool) { - store := prefix.NewStore(ctx.KVStore(k.key), types.RewardPeriodKeyPrefix) - bz := store.Get([]byte(collateralType)) - if bz == nil { - return types.RewardPeriod{}, false - } - var rp types.RewardPeriod - k.cdc.MustUnmarshalBinaryBare(bz, &rp) - return rp, true -} - -// SetRewardPeriod sets the reward period in the store for the input deno, -func (k Keeper) SetRewardPeriod(ctx sdk.Context, rp types.RewardPeriod) { - store := prefix.NewStore(ctx.KVStore(k.key), types.RewardPeriodKeyPrefix) - bz := k.cdc.MustMarshalBinaryBare(rp) - store.Set([]byte(rp.CollateralType), bz) -} - -// DeleteRewardPeriod deletes the reward period in the store for the input collateral type, -func (k Keeper) DeleteRewardPeriod(ctx sdk.Context, collateralType string) { - store := prefix.NewStore(ctx.KVStore(k.key), types.RewardPeriodKeyPrefix) - store.Delete([]byte(collateralType)) -} - -// IterateRewardPeriods iterates over all reward period objects in the store and preforms a callback function -func (k Keeper) IterateRewardPeriods(ctx sdk.Context, cb func(rp types.RewardPeriod) (stop bool)) { - store := prefix.NewStore(ctx.KVStore(k.key), types.RewardPeriodKeyPrefix) - iterator := sdk.KVStorePrefixIterator(store, []byte{}) - defer iterator.Close() - for ; iterator.Valid(); iterator.Next() { - var rp types.RewardPeriod - k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &rp) - if cb(rp) { - break - } - } -} - -// GetAllRewardPeriods returns all reward periods in the store -func (k Keeper) GetAllRewardPeriods(ctx sdk.Context) types.RewardPeriods { - rps := types.RewardPeriods{} - k.IterateRewardPeriods(ctx, func(rp types.RewardPeriod) (stop bool) { - rps = append(rps, rp) - return false - }) - return rps -} - -// GetNextClaimPeriodID returns the highest claim period id in the store for the input collateral type -func (k Keeper) GetNextClaimPeriodID(ctx sdk.Context, collateralType string) uint64 { - store := prefix.NewStore(ctx.KVStore(k.key), types.NextClaimPeriodIDPrefix) - bz := store.Get([]byte(collateralType)) - if bz == nil { - k.SetNextClaimPeriodID(ctx, collateralType, 1) - return uint64(1) - } - return types.BytesToUint64(bz) -} - -// SetNextClaimPeriodID sets the highest claim period id in the store for the input collateral type -func (k Keeper) SetNextClaimPeriodID(ctx sdk.Context, collateralType string, id uint64) { - store := prefix.NewStore(ctx.KVStore(k.key), types.NextClaimPeriodIDPrefix) - store.Set([]byte(collateralType), sdk.Uint64ToBigEndian(id)) -} - -// IterateClaimPeriodIDKeysAndValues iterates over the claim period id (value) and collateral type (key) of each claim period id in the store and performs a callback function -func (k Keeper) IterateClaimPeriodIDKeysAndValues(ctx sdk.Context, cb func(collateralType string, id uint64) (stop bool)) { - store := prefix.NewStore(ctx.KVStore(k.key), types.NextClaimPeriodIDPrefix) - iterator := sdk.KVStorePrefixIterator(store, []byte{}) - defer iterator.Close() - for ; iterator.Valid(); iterator.Next() { - id := types.BytesToUint64(iterator.Value()) - collateralType := string(iterator.Key()) - if cb(collateralType, id) { - break - } - } -} - -// GetAllClaimPeriodIDPairs returns all collateralType:nextClaimPeriodID pairs in the store -func (k Keeper) GetAllClaimPeriodIDPairs(ctx sdk.Context) types.GenesisClaimPeriodIDs { - ids := types.GenesisClaimPeriodIDs{} - k.IterateClaimPeriodIDKeysAndValues(ctx, func(collateralType string, id uint64) (stop bool) { - genID := types.GenesisClaimPeriodID{ - CollateralType: collateralType, - ID: id, - } - ids = append(ids, genID) - return false - }) - return ids -} - -// GetClaimPeriod returns claim period in the store for the input ID and collateral type and a boolean for if it was found -func (k Keeper) GetClaimPeriod(ctx sdk.Context, id uint64, collateralType string) (types.ClaimPeriod, bool) { - var cp types.ClaimPeriod - store := prefix.NewStore(ctx.KVStore(k.key), types.ClaimPeriodKeyPrefix) - bz := store.Get(types.GetClaimPeriodPrefix(collateralType, id)) - if bz == nil { - return types.ClaimPeriod{}, false - } - k.cdc.MustUnmarshalBinaryBare(bz, &cp) - return cp, true -} - -// SetClaimPeriod sets the claim period in the store for the input ID and collateral type -func (k Keeper) SetClaimPeriod(ctx sdk.Context, cp types.ClaimPeriod) { - store := prefix.NewStore(ctx.KVStore(k.key), types.ClaimPeriodKeyPrefix) - bz := k.cdc.MustMarshalBinaryBare(cp) - store.Set(types.GetClaimPeriodPrefix(cp.CollateralType, cp.ID), bz) -} - -// DeleteClaimPeriod deletes the claim period in the store for the input ID and collateral type -func (k Keeper) DeleteClaimPeriod(ctx sdk.Context, id uint64, collateralType string) { - store := prefix.NewStore(ctx.KVStore(k.key), types.ClaimPeriodKeyPrefix) - store.Delete(types.GetClaimPeriodPrefix(collateralType, id)) -} - -// IterateClaimPeriods iterates over all claim period objects in the store and preforms a callback function -func (k Keeper) IterateClaimPeriods(ctx sdk.Context, cb func(cp types.ClaimPeriod) (stop bool)) { - store := prefix.NewStore(ctx.KVStore(k.key), types.ClaimPeriodKeyPrefix) - iterator := sdk.KVStorePrefixIterator(store, []byte{}) - defer iterator.Close() - for ; iterator.Valid(); iterator.Next() { - var cp types.ClaimPeriod - k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &cp) - if cb(cp) { - break - } - } -} - -// GetAllClaimPeriods returns all ClaimPeriod objects in the store -func (k Keeper) GetAllClaimPeriods(ctx sdk.Context) types.ClaimPeriods { - cps := types.ClaimPeriods{} - k.IterateClaimPeriods(ctx, func(cp types.ClaimPeriod) (stop bool) { - cps = append(cps, cp) - return false - }) - return cps -} - // GetClaim returns the claim in the store corresponding the the input address collateral type and id and a boolean for if the claim was found -func (k Keeper) GetClaim(ctx sdk.Context, addr sdk.AccAddress, collateralType string, id uint64) (types.Claim, bool) { +func (k Keeper) GetClaim(ctx sdk.Context, addr sdk.AccAddress) (types.USDXMintingClaim, bool) { store := prefix.NewStore(ctx.KVStore(k.key), types.ClaimKeyPrefix) - bz := store.Get(types.GetClaimPrefix(addr, collateralType, id)) + bz := store.Get(addr) if bz == nil { - return types.Claim{}, false + return types.USDXMintingClaim{}, false } - var c types.Claim + var c types.USDXMintingClaim k.cdc.MustUnmarshalBinaryBare(bz, &c) return c, true } // SetClaim sets the claim in the store corresponding to the input address, collateral type, and id -func (k Keeper) SetClaim(ctx sdk.Context, c types.Claim) { +func (k Keeper) SetClaim(ctx sdk.Context, c types.USDXMintingClaim) { store := prefix.NewStore(ctx.KVStore(k.key), types.ClaimKeyPrefix) bz := k.cdc.MustMarshalBinaryBare(c) - store.Set(types.GetClaimPrefix(c.Owner, c.CollateralType, c.ClaimPeriodID), bz) + store.Set(c.Owner, bz) } // DeleteClaim deletes the claim in the store corresponding to the input address, collateral type, and id -func (k Keeper) DeleteClaim(ctx sdk.Context, owner sdk.AccAddress, collateralType string, id uint64) { +func (k Keeper) DeleteClaim(ctx sdk.Context, owner sdk.AccAddress) { store := prefix.NewStore(ctx.KVStore(k.key), types.ClaimKeyPrefix) - store.Delete(types.GetClaimPrefix(owner, collateralType, id)) + store.Delete(owner) } // IterateClaims iterates over all claim objects in the store and preforms a callback function -func (k Keeper) IterateClaims(ctx sdk.Context, cb func(c types.Claim) (stop bool)) { +func (k Keeper) IterateClaims(ctx sdk.Context, cb func(c types.USDXMintingClaim) (stop bool)) { store := prefix.NewStore(ctx.KVStore(k.key), types.ClaimKeyPrefix) iterator := sdk.KVStorePrefixIterator(store, []byte{}) defer iterator.Close() for ; iterator.Valid(); iterator.Next() { - var c types.Claim + var c types.USDXMintingClaim k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &c) if cb(c) { break @@ -221,28 +78,61 @@ func (k Keeper) IterateClaims(ctx sdk.Context, cb func(c types.Claim) (stop bool } // GetAllClaims returns all Claim objects in the store -func (k Keeper) GetAllClaims(ctx sdk.Context) types.Claims { - cs := types.Claims{} - k.IterateClaims(ctx, func(c types.Claim) (stop bool) { +func (k Keeper) GetAllClaims(ctx sdk.Context) types.USDXMintingClaims { + cs := types.USDXMintingClaims{} + k.IterateClaims(ctx, func(c types.USDXMintingClaim) (stop bool) { cs = append(cs, c) return false }) return cs } -// GetPreviousBlockTime get the blocktime for the previous block -func (k Keeper) GetPreviousBlockTime(ctx sdk.Context) (blockTime time.Time, found bool) { - store := prefix.NewStore(ctx.KVStore(k.key), types.PreviousBlockTimeKey) - b := store.Get([]byte{}) - if b == nil { +// GetPreviousAccrualTime returns the last time a collateral type accrued rewards +func (k Keeper) GetPreviousAccrualTime(ctx sdk.Context, ctype string) (blockTime time.Time, found bool) { + store := prefix.NewStore(ctx.KVStore(k.key), types.BlockTimeKey) + bz := store.Get([]byte(ctype)) + if bz == nil { return time.Time{}, false } - k.cdc.MustUnmarshalBinaryBare(b, &blockTime) + k.cdc.MustUnmarshalBinaryBare(bz, &blockTime) return blockTime, true } -// SetPreviousBlockTime set the time of the previous block -func (k Keeper) SetPreviousBlockTime(ctx sdk.Context, blockTime time.Time) { - store := prefix.NewStore(ctx.KVStore(k.key), types.PreviousBlockTimeKey) - store.Set([]byte{}, k.cdc.MustMarshalBinaryBare(blockTime)) +// SetPreviousAccrualTime sets the last time a collateral type accrued rewards +func (k Keeper) SetPreviousAccrualTime(ctx sdk.Context, ctype string, blockTime time.Time) { + store := prefix.NewStore(ctx.KVStore(k.key), types.BlockTimeKey) + store.Set([]byte(ctype), k.cdc.MustMarshalBinaryBare(blockTime)) +} + +// IterateAccrualTimes iterates over all previous accrual times and preforms a callback function +func (k Keeper) IterateAccrualTimes(ctx sdk.Context, cb func(string, time.Time) (stop bool)) { + store := prefix.NewStore(ctx.KVStore(k.key), types.BlockTimeKey) + iterator := sdk.KVStorePrefixIterator(store, []byte{}) + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + var accrualTime time.Time + var collateralType string + k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &collateralType) + k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &accrualTime) + if cb(collateralType, accrualTime) { + break + } + } +} + +// GetRewardFactor returns the current reward factor for an individual collateral type +func (k Keeper) GetRewardFactor(ctx sdk.Context, ctype string) (factor sdk.Dec, found bool) { + store := prefix.NewStore(ctx.KVStore(k.key), types.RewardFactorKey) + bz := store.Get([]byte(ctype)) + if bz == nil { + return sdk.ZeroDec(), false + } + k.cdc.MustUnmarshalBinaryBare(bz, &factor) + return factor, true +} + +// SetRewardFactor sets the current reward factor for an individual collateral type +func (k Keeper) SetRewardFactor(ctx sdk.Context, ctype string, factor sdk.Dec) { + store := prefix.NewStore(ctx.KVStore(k.key), types.RewardFactorKey) + store.Set([]byte(ctype), k.cdc.MustMarshalBinaryBare(factor)) } diff --git a/x/incentive/keeper/keeper_test.go b/x/incentive/keeper/keeper_test.go index 1b1c6b29..5d25a312 100644 --- a/x/incentive/keeper/keeper_test.go +++ b/x/incentive/keeper/keeper_test.go @@ -2,12 +2,13 @@ package keeper_test import ( "testing" - "time" "github.com/stretchr/testify/suite" 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/auth/vesting" supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported" abci "github.com/tendermint/tendermint/abci/types" @@ -33,7 +34,7 @@ func (suite *KeeperTestSuite) SetupTest() { tApp := app.NewTestApp() ctx := tApp.NewContext(true, abci.Header{Height: 1, Time: tmtime.Now()}) tApp.InitializeFromGenesisStates() - _, addrs := app.GeneratePrivKeyAddressPairs(1) + _, addrs := app.GeneratePrivKeyAddressPairs(5) keeper := tApp.GetIncentiveKeeper() suite.app = tApp suite.ctx = ctx @@ -51,129 +52,63 @@ func (suite *KeeperTestSuite) getModuleAccount(name string) supplyexported.Modul return sk.GetModuleAccount(suite.ctx, name) } -func (suite *KeeperTestSuite) TestGetSetDeleteRewardPeriod() { - rp := types.NewRewardPeriod("bnb", suite.ctx.BlockTime(), suite.ctx.BlockTime().Add(time.Hour*168), c("ukava", 100000000), suite.ctx.BlockTime().Add(time.Hour*168*2), types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33"))}) - _, found := suite.keeper.GetRewardPeriod(suite.ctx, "bnb") - suite.False(found) - suite.NotPanics(func() { - suite.keeper.SetRewardPeriod(suite.ctx, rp) - }) - testRP, found := suite.keeper.GetRewardPeriod(suite.ctx, "bnb") - suite.True(found) - suite.Equal(rp, testRP) - suite.NotPanics(func() { - suite.keeper.DeleteRewardPeriod(suite.ctx, "bnb") - }) - _, found = suite.keeper.GetRewardPeriod(suite.ctx, "bnb") - suite.False(found) -} - -func (suite *KeeperTestSuite) TestGetSetDeleteClaimPeriod() { - cp := types.NewClaimPeriod("bnb", 1, suite.ctx.BlockTime().Add(time.Hour*168), types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33"))}) - _, found := suite.keeper.GetClaimPeriod(suite.ctx, 1, "bnb") - suite.False(found) - suite.NotPanics(func() { - suite.keeper.SetClaimPeriod(suite.ctx, cp) - }) - testCP, found := suite.keeper.GetClaimPeriod(suite.ctx, 1, "bnb") - suite.True(found) - suite.Equal(cp, testCP) - suite.NotPanics(func() { - suite.keeper.DeleteClaimPeriod(suite.ctx, 1, "bnb") - }) - _, found = suite.keeper.GetClaimPeriod(suite.ctx, 1, "bnb") - suite.False(found) -} - -func (suite *KeeperTestSuite) TestGetSetClaimPeriodID() { - suite.NotPanics(func() { - suite.keeper.GetNextClaimPeriodID(suite.ctx, "yolo") - }) - suite.NotPanics(func() { - suite.keeper.SetNextClaimPeriodID(suite.ctx, "bnb", 1) - }) - testID := suite.keeper.GetNextClaimPeriodID(suite.ctx, "bnb") - suite.Equal(uint64(1), testID) - testID = suite.keeper.GetNextClaimPeriodID(suite.ctx, "yolo") - suite.Equal(uint64(1), testID) -} - func (suite *KeeperTestSuite) TestGetSetDeleteClaim() { - c := types.NewClaim(suite.addrs[0], c("ukava", 1000000), "bnb", 1) - _, found := suite.keeper.GetClaim(suite.ctx, suite.addrs[0], "bnb", 1) - suite.False(found) - suite.NotPanics(func() { + c := types.NewUSDXMintingClaim(suite.addrs[0], c("ukava", 1000000), types.RewardIndexes{types.NewRewardIndex("bnb-a", sdk.ZeroDec())}) + _, found := suite.keeper.GetClaim(suite.ctx, suite.addrs[0]) + suite.Require().False(found) + suite.Require().NotPanics(func() { suite.keeper.SetClaim(suite.ctx, c) }) - testC, found := suite.keeper.GetClaim(suite.ctx, suite.addrs[0], "bnb", 1) - suite.True(found) - suite.Equal(c, testC) - suite.NotPanics(func() { - suite.keeper.DeleteClaim(suite.ctx, suite.addrs[0], "bnb", 1) + testC, found := suite.keeper.GetClaim(suite.ctx, suite.addrs[0]) + suite.Require().True(found) + suite.Require().Equal(c, testC) + suite.Require().NotPanics(func() { + suite.keeper.DeleteClaim(suite.ctx, suite.addrs[0]) }) - _, found = suite.keeper.GetClaim(suite.ctx, suite.addrs[0], "bnb", 1) - suite.False(found) + _, found = suite.keeper.GetClaim(suite.ctx, suite.addrs[0]) + suite.Require().False(found) } -func (suite *KeeperTestSuite) TestIterateMethods() { - suite.addObjectsToStore() // adds 2 objects of each type to the store - - var rewardPeriods types.RewardPeriods - suite.keeper.IterateRewardPeriods(suite.ctx, func(rp types.RewardPeriod) (stop bool) { - rewardPeriods = append(rewardPeriods, rp) - return false - }) - suite.Equal(2, len(rewardPeriods)) - - var claimPeriods types.ClaimPeriods - suite.keeper.IterateClaimPeriods(suite.ctx, func(cp types.ClaimPeriod) (stop bool) { - claimPeriods = append(claimPeriods, cp) - return false - }) - suite.Equal(2, len(claimPeriods)) - - var claims types.Claims - suite.keeper.IterateClaims(suite.ctx, func(c types.Claim) (stop bool) { +func (suite *KeeperTestSuite) TestIterateClaims() { + for i := 0; i < len(suite.addrs); i++ { + c := types.NewUSDXMintingClaim(suite.addrs[i], c("ukava", 100000), types.RewardIndexes{types.NewRewardIndex("bnb-a", sdk.ZeroDec())}) + suite.Require().NotPanics(func() { + suite.keeper.SetClaim(suite.ctx, c) + }) + } + claims := types.USDXMintingClaims{} + suite.keeper.IterateClaims(suite.ctx, func(c types.USDXMintingClaim) bool { claims = append(claims, c) return false }) - suite.Equal(2, len(claims)) - - var genIDs types.GenesisClaimPeriodIDs - suite.keeper.IterateClaimPeriodIDKeysAndValues(suite.ctx, func(collateralType string, id uint64) (stop bool) { - genID := types.GenesisClaimPeriodID{CollateralType: collateralType, ID: id} - genIDs = append(genIDs, genID) - return false - }) - suite.Equal(2, len(genIDs)) -} - -func (suite *KeeperTestSuite) addObjectsToStore() { - rp1 := types.NewRewardPeriod("bnb", suite.ctx.BlockTime(), suite.ctx.BlockTime().Add(time.Hour*168), c("ukava", 100000000), suite.ctx.BlockTime().Add(time.Hour*168*2), types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33"))}) - rp2 := types.NewRewardPeriod("xrp", suite.ctx.BlockTime(), suite.ctx.BlockTime().Add(time.Hour*168), c("ukava", 100000000), suite.ctx.BlockTime().Add(time.Hour*168*2), types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33"))}) - suite.keeper.SetRewardPeriod(suite.ctx, rp1) - suite.keeper.SetRewardPeriod(suite.ctx, rp2) - - cp1 := types.NewClaimPeriod("bnb", 1, suite.ctx.BlockTime().Add(time.Hour*168), types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33"))}) - cp2 := types.NewClaimPeriod("xrp", 1, suite.ctx.BlockTime().Add(time.Hour*168), types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33"))}) - suite.keeper.SetClaimPeriod(suite.ctx, cp1) - suite.keeper.SetClaimPeriod(suite.ctx, cp2) - - suite.keeper.SetNextClaimPeriodID(suite.ctx, "bnb", 2) - suite.keeper.SetNextClaimPeriodID(suite.ctx, "xrp", 2) - - c1 := types.NewClaim(suite.addrs[0], c("ukava", 1000000), "bnb", 1) - c2 := types.NewClaim(suite.addrs[0], c("ukava", 1000000), "xrp", 1) - suite.keeper.SetClaim(suite.ctx, c1) - suite.keeper.SetClaim(suite.ctx, c2) - - params := types.NewParams( - true, types.Rewards{types.NewReward(true, "bnb", c("ukava", 1000000000), time.Hour*7*24, types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33"))}, time.Hour*7*24)}, - ) - suite.keeper.SetParams(suite.ctx, params) + suite.Require().Equal(len(suite.addrs), len(claims)) + claims = suite.keeper.GetAllClaims(suite.ctx) + suite.Require().Equal(len(suite.addrs), len(claims)) } func TestKeeperTestSuite(t *testing.T) { suite.Run(t, new(KeeperTestSuite)) } + +func createPeriodicVestingAccount(origVesting sdk.Coins, periods vesting.Periods, startTime, endTime int64) (*vesting.PeriodicVestingAccount, error) { + _, addr := app.GeneratePrivKeyAddressPairs(1) + bacc := auth.NewBaseAccountWithAddress(addr[0]) + bacc.Coins = origVesting + bva, err := vesting.NewBaseVestingAccount(&bacc, origVesting, endTime) + if err != nil { + return &vesting.PeriodicVestingAccount{}, err + } + pva := vesting.NewPeriodicVestingAccountRaw(bva, startTime, periods) + err = pva.Validate() + if err != nil { + return &vesting.PeriodicVestingAccount{}, err + } + return pva, nil +} + +// Avoid cluttering test cases with long function names +func i(in int64) sdk.Int { return sdk.NewInt(in) } +func d(str string) sdk.Dec { return sdk.MustNewDecFromStr(str) } +func c(denom string, amount int64) sdk.Coin { return sdk.NewInt64Coin(denom, amount) } +func cs(coins ...sdk.Coin) sdk.Coins { return sdk.NewCoins(coins...) } diff --git a/x/incentive/keeper/params.go b/x/incentive/keeper/params.go index 0d6b6f78..a1306bcf 100644 --- a/x/incentive/keeper/params.go +++ b/x/incentive/keeper/params.go @@ -1,6 +1,8 @@ package keeper import ( + "time" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/kava-labs/kava/x/incentive/types" @@ -17,3 +19,31 @@ func (k Keeper) GetParams(ctx sdk.Context) types.Params { func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { k.paramSubspace.SetParamSet(ctx, ¶ms) } + +// GetRewardPeriod returns the reward period with the specified collateral type if it's found in the params +func (k Keeper) GetRewardPeriod(ctx sdk.Context, collateralType string) (types.RewardPeriod, bool) { + params := k.GetParams(ctx) + for _, rp := range params.RewardPeriods { + if rp.CollateralType == collateralType { + return rp, true + } + } + return types.RewardPeriod{}, false +} + +// GetMultiplier returns the multiplier with the specified name if it's found in the params +func (k Keeper) GetMultiplier(ctx sdk.Context, name types.MultiplierName) (types.Multiplier, bool) { + params := k.GetParams(ctx) + for _, m := range params.ClaimMultipliers { + if m.Name == name { + return m, true + } + } + return types.Multiplier{}, false +} + +// GetClaimEnd returns the claim end time for the params +func (k Keeper) GetClaimEnd(ctx sdk.Context) time.Time { + params := k.GetParams(ctx) + return params.ClaimEnd +} diff --git a/x/incentive/keeper/payout.go b/x/incentive/keeper/payout.go index 6da53557..cfc2c80e 100644 --- a/x/incentive/keeper/payout.go +++ b/x/incentive/keeper/payout.go @@ -1,8 +1,6 @@ package keeper import ( - "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth" @@ -14,42 +12,48 @@ import ( validatorvesting "github.com/kava-labs/kava/x/validator-vesting" ) -// PayoutClaim sends the timelocked claim coins to the input address -func (k Keeper) PayoutClaim(ctx sdk.Context, addr sdk.AccAddress, collateralType string, id uint64, multiplierName types.MultiplierName) error { - claim, found := k.GetClaim(ctx, addr, collateralType, id) +// ClaimReward sends the reward amount to the input address and zero's out the claim in the store +func (k Keeper) ClaimReward(ctx sdk.Context, addr sdk.AccAddress, multiplierName types.MultiplierName) error { + claim, found := k.GetClaim(ctx, addr) if !found { - return sdkerrors.Wrapf(types.ErrClaimNotFound, "id: %d, collateral type %s, address: %s", id, collateralType, addr) - } - claimPeriod, found := k.GetClaimPeriod(ctx, id, collateralType) - if !found { - return sdkerrors.Wrapf(types.ErrClaimPeriodNotFound, "id: %d, collateral type: %s", id, collateralType) + return sdkerrors.Wrapf(types.ErrClaimNotFound, "address: %s", addr) } - multiplier, found := claimPeriod.GetMultiplier(multiplierName) + multiplier, found := k.GetMultiplier(ctx, multiplierName) if !found { return sdkerrors.Wrapf(types.ErrInvalidMultiplier, string(multiplierName)) } - rewardAmount := sdk.NewDecFromInt(claim.Reward.Amount).Mul(multiplier.Factor).RoundInt() + claimEnd := k.GetClaimEnd(ctx) + + if ctx.BlockTime().After(claimEnd) { + return sdkerrors.Wrapf(types.ErrClaimExpired, "block time %s > claim end time %s", ctx.BlockTime(), claimEnd) + } + + claim, err := k.SynchronizeClaim(ctx, claim) + if err != nil { + return err + } + + rewardAmount := claim.Reward.Amount.ToDec().Mul(multiplier.Factor).RoundInt() if rewardAmount.IsZero() { return types.ErrZeroClaim } rewardCoin := sdk.NewCoin(claim.Reward.Denom, rewardAmount) length := ctx.BlockTime().AddDate(0, int(multiplier.MonthsLockup), 0).Unix() - ctx.BlockTime().Unix() - err := k.SendTimeLockedCoinsToAccount(ctx, types.IncentiveMacc, addr, sdk.NewCoins(rewardCoin), length) + err = k.SendTimeLockedCoinsToAccount(ctx, types.IncentiveMacc, addr, sdk.NewCoins(rewardCoin), length) if err != nil { return err } - k.DeleteClaim(ctx, addr, collateralType, id) + k.ZeroClaim(ctx, claim) ctx.EventManager().EmitEvent( sdk.NewEvent( types.EventTypeClaim, sdk.NewAttribute(types.AttributeKeyClaimedBy, addr.String()), sdk.NewAttribute(types.AttributeKeyClaimAmount, claim.Reward.String()), - sdk.NewAttribute(types.AttributeKeyClaimPeriod, fmt.Sprintf("%d", claim.ClaimPeriodID)), ), ) return nil @@ -112,75 +116,6 @@ func (k Keeper) SendTimeLockedCoinsToBaseAccount(ctx sdk.Context, senderModule s return nil } -// DeleteExpiredClaimsAndClaimPeriods deletes expired claim periods and their associated claims -func (k Keeper) DeleteExpiredClaimsAndClaimPeriods(ctx sdk.Context) { - k.IterateClaimPeriods(ctx, func(cp types.ClaimPeriod) (stop bool) { - if !cp.End.Before(ctx.BlockTime()) { - return false - } - k.IterateClaims(ctx, func(c types.Claim) (stop bool) { - if !(c.CollateralType == cp.CollateralType && c.ClaimPeriodID == cp.ID) { - return false - } - k.DeleteClaim(ctx, c.Owner, c.CollateralType, c.ClaimPeriodID) - return false - }) - k.DeleteClaimPeriod(ctx, cp.ID, cp.CollateralType) - ctx.EventManager().EmitEvent( - sdk.NewEvent( - types.EventTypeClaimPeriodExpiry, - sdk.NewAttribute(types.AttributeKeyClaimPeriod, cp.String()), - ), - ) - - return false - }) -} - -// GetActiveClaimsByAddressAndCollateralType returns all claims for a specific user and address and a bool for if any were found -func (k Keeper) GetActiveClaimsByAddressAndCollateralType(ctx sdk.Context, addr sdk.AccAddress, collateralType string) (claims types.Claims, found bool) { - found = false - k.IterateClaimPeriods(ctx, func(cp types.ClaimPeriod) (stop bool) { - if cp.CollateralType != collateralType { - return false - } - c, hasClaim := k.GetClaim(ctx, addr, cp.CollateralType, cp.ID) - if !hasClaim { - return false - } - found = true - claims = append(claims, c) - return false - }) - return claims, found -} - -// GetAllClaimsByAddressAndCollateralType returns all claims for a specific user and address and a bool for if any were found -func (k Keeper) GetAllClaimsByAddressAndCollateralType(ctx sdk.Context, addr sdk.AccAddress, collateralType string) (claims types.AugmentedClaims, found bool) { - found = false - k.IterateClaimPeriods(ctx, func(cp types.ClaimPeriod) (stop bool) { - if cp.CollateralType != collateralType { - return false - } - c, hasClaim := k.GetClaim(ctx, addr, cp.CollateralType, cp.ID) - if !hasClaim { - return false - } - ac := types.NewAugmentedClaim(c, true) - found = true - claims = append(claims, ac) - return false - }) - nextClaimID := k.GetNextClaimPeriodID(ctx, collateralType) - c, hasClaim := k.GetClaim(ctx, addr, collateralType, nextClaimID) - if !hasClaim { - return claims, found - } - ac := types.NewAugmentedClaim(c, false) - claims = append(claims, ac) - return claims, true -} - // addCoinsToVestingSchedule adds coins to the input account's vesting schedule where length is the amount of time (from the current block time), in seconds, that the coins will be vesting for // the input address must be a periodic vesting account func (k Keeper) addCoinsToVestingSchedule(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins, length int64) { diff --git a/x/incentive/keeper/payout_test.go b/x/incentive/keeper/payout_test.go index 10d922f6..7091a2b6 100644 --- a/x/incentive/keeper/payout_test.go +++ b/x/incentive/keeper/payout_test.go @@ -2,119 +2,154 @@ package keeper_test import ( "errors" + "fmt" "strings" "time" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth/vesting" abci "github.com/tendermint/tendermint/abci/types" + "github.com/cosmos/cosmos-sdk/x/auth" "github.com/kava-labs/kava/app" - "github.com/kava-labs/kava/x/cdp" + cdptypes "github.com/kava-labs/kava/x/cdp/types" "github.com/kava-labs/kava/x/incentive/types" "github.com/kava-labs/kava/x/kavadist" validatorvesting "github.com/kava-labs/kava/x/validator-vesting" - "github.com/tendermint/tendermint/crypto" ) -func (suite *KeeperTestSuite) setupChain() { - // creates a new app state with 4 funded addresses and 1 module account - tApp := app.NewTestApp() - ctx := tApp.NewContext(true, abci.Header{Height: 1, Time: time.Unix(100, 0)}) - _, addrs := app.GeneratePrivKeyAddressPairs(4) - authGS := app.NewAuthGenState( - addrs, - []sdk.Coins{ - cs(c("ukava", 400)), - cs(c("ukava", 400)), - cs(c("ukava", 400)), - cs(c("ukava", 400)), +func (suite *KeeperTestSuite) TestPayoutClaim() { + type args struct { + ctype string + rewardsPerSecond sdk.Coin + initialTime time.Time + initialCollateral sdk.Coin + initialPrincipal sdk.Coin + multipliers types.Multipliers + multiplier types.MultiplierName + timeElapsed int + expectedBalance sdk.Coins + expectedPeriods vesting.Periods + isPeriodicVestingAccount bool + } + type errArgs struct { + expectPass bool + contains string + } + type test struct { + name string + args args + errArgs errArgs + } + testCases := []test{ + { + "valid 1 day", + args{ + ctype: "bnb-a", + rewardsPerSecond: c("ukava", 122354), + initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + initialCollateral: c("bnb", 1000000000000), + initialPrincipal: c("usdx", 10000000000), + multipliers: types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, + multiplier: types.MultiplierName("large"), + timeElapsed: 86400, + expectedBalance: cs(c("usdx", 10000000000), c("ukava", 10571385600)), + expectedPeriods: vesting.Periods{vesting.Period{Length: 31536000, Amount: cs(c("ukava", 10571385600))}}, + isPeriodicVestingAccount: true, + }, + errArgs{ + expectPass: true, + contains: "", + }, + }, + { + "invalid zero rewards", + args{ + ctype: "bnb-a", + rewardsPerSecond: c("ukava", 0), + initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + initialCollateral: c("bnb", 1000000000000), + initialPrincipal: c("usdx", 10000000000), + multipliers: types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, + multiplier: types.MultiplierName("large"), + timeElapsed: 86400, + expectedBalance: cs(c("usdx", 10000000000)), + expectedPeriods: vesting.Periods{}, + isPeriodicVestingAccount: false, + }, + errArgs{ + expectPass: false, + contains: "claim amount rounds to zero", + }, + }, + } + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupWithCDPGenState() + suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime) + + // setup incentive state + params := types.NewParams( + types.RewardPeriods{types.NewRewardPeriod(true, tc.args.ctype, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)}, + tc.args.multipliers, + tc.args.initialTime.Add(time.Hour*24*365*5), + ) + suite.keeper.SetParams(suite.ctx, params) + suite.keeper.SetPreviousAccrualTime(suite.ctx, tc.args.ctype, tc.args.initialTime) + suite.keeper.SetRewardFactor(suite.ctx, tc.args.ctype, sdk.ZeroDec()) + + // setup account state + sk := suite.app.GetSupplyKeeper() + err := sk.MintCoins(suite.ctx, cdptypes.ModuleName, sdk.NewCoins(tc.args.initialCollateral)) + suite.Require().NoError(err) + err = sk.SendCoinsFromModuleToAccount(suite.ctx, cdptypes.ModuleName, suite.addrs[0], sdk.NewCoins(tc.args.initialCollateral)) + suite.Require().NoError(err) + + // setup kavadist state + err = sk.MintCoins(suite.ctx, kavadist.ModuleName, cs(c("ukava", 1000000000000))) + suite.Require().NoError(err) + + // setup cdp state + cdpKeeper := suite.app.GetCDPKeeper() + err = cdpKeeper.AddCdp(suite.ctx, suite.addrs[0], tc.args.initialCollateral, tc.args.initialPrincipal, tc.args.ctype) + suite.Require().NoError(err) + + claim, found := suite.keeper.GetClaim(suite.ctx, suite.addrs[0]) + suite.Require().True(found) + suite.Require().Equal(sdk.ZeroDec(), claim.RewardIndexes[0].RewardFactor) + + updatedBlockTime := suite.ctx.BlockTime().Add(time.Duration(int(time.Second) * tc.args.timeElapsed)) + suite.ctx = suite.ctx.WithBlockTime(updatedBlockTime) + rewardPeriod, found := suite.keeper.GetRewardPeriod(suite.ctx, tc.args.ctype) + suite.Require().True(found) + err = suite.keeper.AccumulateRewards(suite.ctx, rewardPeriod) + suite.Require().NoError(err) + + err = suite.keeper.ClaimReward(suite.ctx, suite.addrs[0], tc.args.multiplier) + + if tc.errArgs.expectPass { + suite.Require().NoError(err) + ak := suite.app.GetAccountKeeper() + acc := ak.GetAccount(suite.ctx, suite.addrs[0]) + suite.Require().Equal(tc.args.expectedBalance, acc.GetCoins()) + + if tc.args.isPeriodicVestingAccount { + vacc, ok := acc.(*vesting.PeriodicVestingAccount) + suite.Require().True(ok) + suite.Require().Equal(tc.args.expectedPeriods, vacc.VestingPeriods) + } + + claim, found := suite.keeper.GetClaim(suite.ctx, suite.addrs[0]) + fmt.Println(claim) + suite.Require().True(found) + suite.Require().Equal(c("ukava", 0), claim.Reward) + } else { + suite.Require().Error(err) + suite.Require().True(strings.Contains(err.Error(), tc.errArgs.contains)) + } }) - tApp.InitializeFromGenesisStates( - authGS, - ) - supplyKeeper := tApp.GetSupplyKeeper() - macc := supplyKeeper.GetModuleAccount(ctx, kavadist.ModuleName) - err := supplyKeeper.MintCoins(ctx, macc.GetName(), cs(c("ukava", 600))) - suite.Require().NoError(err) - - // sets addrs[0] to be a periodic vesting account - ak := tApp.GetAccountKeeper() - acc := ak.GetAccount(ctx, addrs[0]) - bacc := auth.NewBaseAccount(acc.GetAddress(), acc.GetCoins(), acc.GetPubKey(), acc.GetAccountNumber(), acc.GetSequence()) - periods := vesting.Periods{ - vesting.Period{Length: int64(1), Amount: cs(c("ukava", 100))}, - vesting.Period{Length: int64(2), Amount: cs(c("ukava", 100))}, - vesting.Period{Length: int64(8), Amount: cs(c("ukava", 100))}, - vesting.Period{Length: int64(5), Amount: cs(c("ukava", 100))}, } - bva, err2 := vesting.NewBaseVestingAccount(bacc, cs(c("ukava", 400)), ctx.BlockTime().Unix()+16) - suite.Require().NoError(err2) - pva := vesting.NewPeriodicVestingAccountRaw(bva, ctx.BlockTime().Unix(), periods) - ak.SetAccount(ctx, pva) - - // sets addrs[2] to be a validator vesting account - acc = ak.GetAccount(ctx, addrs[2]) - bacc = auth.NewBaseAccount(acc.GetAddress(), acc.GetCoins(), acc.GetPubKey(), acc.GetAccountNumber(), acc.GetSequence()) - bva, err2 = vesting.NewBaseVestingAccount(bacc, cs(c("ukava", 400)), ctx.BlockTime().Unix()+16) - suite.Require().NoError(err2) - vva := validatorvesting.NewValidatorVestingAccountRaw(bva, ctx.BlockTime().Unix(), periods, sdk.ConsAddress{}, nil, 90) - ak.SetAccount(ctx, vva) - suite.app = tApp - suite.keeper = tApp.GetIncentiveKeeper() - suite.ctx = ctx - suite.addrs = addrs -} - -func (suite *KeeperTestSuite) setupExpiredClaims() { - // creates a new app state with 4 funded addresses - tApp := app.NewTestApp() - ctx := tApp.NewContext(true, abci.Header{Height: 1, Time: time.Unix(100, 0)}) - _, addrs := app.GeneratePrivKeyAddressPairs(4) - authGS := app.NewAuthGenState( - addrs, - []sdk.Coins{ - cs(c("ukava", 400)), - cs(c("ukava", 400)), - cs(c("ukava", 400)), - cs(c("ukava", 400)), - }) - tApp.InitializeFromGenesisStates( - authGS, - ) - - // creates two claim periods, one expired, and one that expires in the future - cp1 := types.NewClaimPeriod("bnb", 1, time.Unix(90, 0), types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))}) - cp2 := types.NewClaimPeriod("xrp", 1, time.Unix(110, 0), types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))}) - suite.keeper = tApp.GetIncentiveKeeper() - suite.keeper.SetClaimPeriod(ctx, cp1) - suite.keeper.SetClaimPeriod(ctx, cp2) - // creates one claim for the non-expired claim period and one claim for the expired claim period - c1 := types.NewClaim(addrs[0], c("ukava", 1000000), "bnb", 1) - c2 := types.NewClaim(addrs[0], c("ukava", 1000000), "xrp", 1) - suite.keeper.SetClaim(ctx, c1) - suite.keeper.SetClaim(ctx, c2) - suite.app = tApp - suite.ctx = ctx - suite.addrs = addrs -} - -func createPeriodicVestingAccount(origVesting sdk.Coins, periods vesting.Periods, startTime, endTime int64) (*vesting.PeriodicVestingAccount, error) { - _, addr := app.GeneratePrivKeyAddressPairs(1) - bacc := auth.NewBaseAccountWithAddress(addr[0]) - bacc.Coins = origVesting - bva, err := vesting.NewBaseVestingAccount(&bacc, origVesting, endTime) - if err != nil { - return &vesting.PeriodicVestingAccount{}, err - } - pva := vesting.NewPeriodicVestingAccountRaw(bva, startTime, periods) - err = pva.Validate() - if err != nil { - return &vesting.PeriodicVestingAccount{}, err - } - return pva, nil } func (suite *KeeperTestSuite) TestSendCoinsToPeriodicVestingAccount() { @@ -391,7 +426,7 @@ func (suite *KeeperTestSuite) TestSendCoinsToPeriodicVestingAccount() { } func (suite *KeeperTestSuite) TestSendCoinsToBaseAccount() { - suite.setupChain() + suite.SetupWithAccountState() // send coins to base account err := suite.keeper.SendTimeLockedCoinsToAccount(suite.ctx, kavadist.ModuleName, suite.addrs[1], cs(c("ukava", 100)), 5) suite.Require().NoError(err) @@ -410,267 +445,59 @@ func (suite *KeeperTestSuite) TestSendCoinsToBaseAccount() { } func (suite *KeeperTestSuite) TestSendCoinsToInvalidAccount() { - suite.setupChain() + suite.SetupWithAccountState() err := suite.keeper.SendTimeLockedCoinsToAccount(suite.ctx, kavadist.ModuleName, suite.addrs[2], cs(c("ukava", 100)), 5) suite.Require().True(errors.Is(err, types.ErrInvalidAccountType)) - macc := suite.getModuleAccount(cdp.ModuleName) + macc := suite.getModuleAccount(cdptypes.ModuleName) err = suite.keeper.SendTimeLockedCoinsToAccount(suite.ctx, kavadist.ModuleName, macc.GetAddress(), cs(c("ukava", 100)), 5) suite.Require().True(errors.Is(err, types.ErrInvalidAccountType)) } -func (suite *KeeperTestSuite) TestDeleteExpiredClaimPeriods() { - suite.setupExpiredClaims() // creates new app state with one non-expired claim period (xrp) and one expired claim period (bnb) as well as a claim that corresponds to each claim period - - // both claim periods are present - _, found := suite.keeper.GetClaimPeriod(suite.ctx, 1, "bnb") - suite.True(found) - _, found = suite.keeper.GetClaimPeriod(suite.ctx, 1, "xrp") - suite.True(found) - // both claims are present - _, found = suite.keeper.GetClaim(suite.ctx, suite.addrs[0], "bnb", 1) - suite.True(found) - _, found = suite.keeper.GetClaim(suite.ctx, suite.addrs[0], "xrp", 1) - suite.True(found) - - // expired claim period and associated claims should get deleted - suite.NotPanics(func() { - suite.keeper.DeleteExpiredClaimsAndClaimPeriods(suite.ctx) - }) - // expired claim period and claim are not found - _, found = suite.keeper.GetClaimPeriod(suite.ctx, 1, "bnb") - suite.False(found) - _, found = suite.keeper.GetClaim(suite.ctx, suite.addrs[0], "bnb", 1) - suite.False(found) - // non-expired claim period and claim are found - _, found = suite.keeper.GetClaimPeriod(suite.ctx, 1, "xrp") - suite.True(found) - _, found = suite.keeper.GetClaim(suite.ctx, suite.addrs[0], "xrp", 1) - suite.True(found) - -} - -func (suite *KeeperTestSuite) TestPayoutClaim() { - type args struct { - claimOwner sdk.AccAddress - collateralType string - id uint64 - multiplier types.MultiplierName - blockTime time.Time - rewards types.Rewards - rewardperiods types.RewardPeriods - claimPeriods types.ClaimPeriods - claims types.Claims - genIDs types.GenesisClaimPeriodIDs - active bool - validatorVesting bool - expectedAccountBalance sdk.Coins - expectedModAccountBalance sdk.Coins - expectedVestingAccount bool - expectedVestingLength int64 - } - type errArgs struct { - expectPass bool - contains string - } - type claimTest struct { - name string - args args - errArgs errArgs - } - testCases := []claimTest{ - { - "valid small claim", - args{ - claimOwner: sdk.AccAddress(crypto.AddressHash([]byte("test"))), - collateralType: "bnb-a", - id: 1, - blockTime: time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC), - rewards: types.Rewards{types.NewReward(true, "bnb-a", c("ukava", 1000000000), time.Hour*7*24, types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))}, time.Hour*7*24)}, - rewardperiods: types.RewardPeriods{types.NewRewardPeriod("bnb-a", time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC).Add(time.Hour*7*24), c("ukava", 1000), time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC).Add(time.Hour*7*24*2), types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))})}, - claimPeriods: types.ClaimPeriods{types.NewClaimPeriod("bnb-a", 1, time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC).Add(time.Hour*7*24), types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))})}, - claims: types.Claims{types.NewClaim(sdk.AccAddress(crypto.AddressHash([]byte("test"))), sdk.NewCoin("ukava", sdk.NewInt(1000)), "bnb-a", 1)}, - genIDs: types.GenesisClaimPeriodIDs{types.GenesisClaimPeriodID{CollateralType: "bnb-a", ID: 2}}, - active: true, - validatorVesting: false, - expectedAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(500)), sdk.NewCoin("bnb", sdk.NewInt(1000)), sdk.NewCoin("btcb", sdk.NewInt(1000))), - expectedModAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(500))), - expectedVestingAccount: true, - expectedVestingLength: time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC).AddDate(0, 1, 0).Unix() - time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC).Unix(), - multiplier: types.Small, - }, - errArgs{ - expectPass: true, - contains: "", - }, - }, - { - "valid large claim", - args{ - claimOwner: sdk.AccAddress(crypto.AddressHash([]byte("test"))), - collateralType: "bnb-a", - id: 1, - blockTime: time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC), - rewards: types.Rewards{types.NewReward(true, "bnb-a", c("ukava", 1000000000), time.Hour*7*24, types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))}, time.Hour*7*24)}, - rewardperiods: types.RewardPeriods{types.NewRewardPeriod("bnb-a", time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC).Add(time.Hour*7*24), c("ukava", 1000), time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC).Add(time.Hour*7*24*2), types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))})}, - claimPeriods: types.ClaimPeriods{types.NewClaimPeriod("bnb-a", 1, time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC).Add(time.Hour*7*24), types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))})}, - claims: types.Claims{types.NewClaim(sdk.AccAddress(crypto.AddressHash([]byte("test"))), sdk.NewCoin("ukava", sdk.NewInt(1000)), "bnb-a", 1)}, - genIDs: types.GenesisClaimPeriodIDs{types.GenesisClaimPeriodID{CollateralType: "bnb-a", ID: 2}}, - active: true, - validatorVesting: false, - expectedAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(1000)), sdk.NewCoin("bnb", sdk.NewInt(1000)), sdk.NewCoin("btcb", sdk.NewInt(1000))), - expectedModAccountBalance: sdk.Coins(nil), - expectedVestingAccount: true, - expectedVestingLength: time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC).AddDate(0, 12, 0).Unix() - time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC).Unix(), - multiplier: types.Large, - }, - errArgs{ - expectPass: true, - contains: "", - }, - }, - { - "valid liquid claim", - args{ - claimOwner: sdk.AccAddress(crypto.AddressHash([]byte("test"))), - collateralType: "bnb-a", - id: 1, - blockTime: time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC), - rewards: types.Rewards{types.NewReward(true, "bnb-a", c("ukava", 1000000000), time.Hour*7*24, types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))}, time.Hour*7*24)}, - rewardperiods: types.RewardPeriods{types.NewRewardPeriod("bnb-a", time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC).Add(time.Hour*7*24), c("ukava", 1000), time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC).Add(time.Hour*7*24*2), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))})}, - claimPeriods: types.ClaimPeriods{types.NewClaimPeriod("bnb-a", 1, time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC).Add(time.Hour*7*24), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))})}, - claims: types.Claims{types.NewClaim(sdk.AccAddress(crypto.AddressHash([]byte("test"))), sdk.NewCoin("ukava", sdk.NewInt(1000)), "bnb-a", 1)}, - genIDs: types.GenesisClaimPeriodIDs{types.GenesisClaimPeriodID{CollateralType: "bnb-a", ID: 2}}, - active: true, - validatorVesting: false, - expectedAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(500)), sdk.NewCoin("bnb", sdk.NewInt(1000)), sdk.NewCoin("btcb", sdk.NewInt(1000))), - expectedModAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(500))), - expectedVestingAccount: false, - expectedVestingLength: 0, - multiplier: types.Small, - }, - errArgs{ - expectPass: true, - contains: "", - }, - }, - { - "no matching claim", - args{ - claimOwner: sdk.AccAddress(crypto.AddressHash([]byte("test"))), - collateralType: "btcb-a", - id: 1, - blockTime: time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC), - rewards: types.Rewards{types.NewReward(true, "bnb-a", c("ukava", 1000000000), time.Hour*7*24, types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))}, time.Hour*7*24)}, - rewardperiods: types.RewardPeriods{types.NewRewardPeriod("bnb-a", time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC).Add(time.Hour*7*24), c("ukava", 1000), time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC).Add(time.Hour*7*24*2), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))})}, - claimPeriods: types.ClaimPeriods{types.NewClaimPeriod("bnb-a", 1, time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC).Add(time.Hour*7*24), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))})}, - claims: types.Claims{types.NewClaim(sdk.AccAddress(crypto.AddressHash([]byte("test"))), sdk.NewCoin("ukava", sdk.NewInt(1000)), "bnb-a", 1)}, - genIDs: types.GenesisClaimPeriodIDs{types.GenesisClaimPeriodID{CollateralType: "bnb-a", ID: 2}}, - active: true, - validatorVesting: false, - expectedAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(500)), sdk.NewCoin("bnb", sdk.NewInt(1000)), sdk.NewCoin("btcb", sdk.NewInt(1000))), - expectedModAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(500))), - expectedVestingAccount: false, - expectedVestingLength: 0, - multiplier: types.Small, - }, - errArgs{ - expectPass: false, - contains: "no claim with input id found for owner and collateral type", - }, - }, - { - "validator vesting claim", - args{ - claimOwner: sdk.AccAddress(crypto.AddressHash([]byte("test"))), - collateralType: "bnb-a", - id: 1, - blockTime: time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC), - rewards: types.Rewards{types.NewReward(true, "bnb-a", c("ukava", 1000000000), time.Hour*7*24, types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))}, time.Hour*7*24)}, - rewardperiods: types.RewardPeriods{types.NewRewardPeriod("bnb-a", time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC).Add(time.Hour*7*24), c("ukava", 1000), time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC).Add(time.Hour*7*24*2), types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))})}, - claimPeriods: types.ClaimPeriods{types.NewClaimPeriod("bnb-a", 1, time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC).Add(time.Hour*7*24), types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))})}, - claims: types.Claims{types.NewClaim(sdk.AccAddress(crypto.AddressHash([]byte("test"))), sdk.NewCoin("ukava", sdk.NewInt(1000)), "bnb-a", 1)}, - genIDs: types.GenesisClaimPeriodIDs{types.GenesisClaimPeriodID{CollateralType: "bnb-a", ID: 2}}, - active: true, - validatorVesting: true, - expectedAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(500)), sdk.NewCoin("bnb", sdk.NewInt(1000)), sdk.NewCoin("btcb", sdk.NewInt(1000))), - expectedModAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(500))), - expectedVestingAccount: false, - expectedVestingLength: 0, - multiplier: types.Small, - }, - errArgs{ - expectPass: false, - contains: "account type not supported", - }, - }, - } - for _, tc := range testCases { - suite.Run(tc.name, func() { - // create new app with one funded account - config := sdk.GetConfig() - app.SetBech32AddressPrefixes(config) - // Initialize test app and set context - tApp := app.NewTestApp() - ctx := tApp.NewContext(true, abci.Header{Height: 1, Time: tc.args.blockTime}) - authGS := app.NewAuthGenState( - []sdk.AccAddress{tc.args.claimOwner}, - []sdk.Coins{ - sdk.NewCoins(sdk.NewCoin("bnb", sdk.NewInt(1000)), sdk.NewCoin("btcb", sdk.NewInt(1000))), - }) - incentiveGS := types.NewGenesisState(types.NewParams(tc.args.active, tc.args.rewards), types.DefaultPreviousBlockTime, tc.args.rewardperiods, tc.args.claimPeriods, tc.args.claims, tc.args.genIDs) - tApp.InitializeFromGenesisStates(authGS, app.GenesisState{types.ModuleName: types.ModuleCdc.MustMarshalJSON(incentiveGS)}) - if tc.args.validatorVesting { - ak := tApp.GetAccountKeeper() - acc := ak.GetAccount(ctx, tc.args.claimOwner) - bacc := auth.NewBaseAccount(acc.GetAddress(), acc.GetCoins(), acc.GetPubKey(), acc.GetAccountNumber(), acc.GetSequence()) - bva, err := vesting.NewBaseVestingAccount( - bacc, - sdk.NewCoins(sdk.NewCoin("bnb", sdk.NewInt(20))), time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC).Unix()+100) - suite.Require().NoError(err) - vva := validatorvesting.NewValidatorVestingAccountRaw( - bva, - time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC).Unix(), - vesting.Periods{ - vesting.Period{Length: 25, Amount: cs(c("bnb", 5))}, - vesting.Period{Length: 25, Amount: cs(c("bnb", 5))}, - vesting.Period{Length: 25, Amount: cs(c("bnb", 5))}, - vesting.Period{Length: 25, Amount: cs(c("bnb", 5))}}, - sdk.ConsAddress(crypto.AddressHash([]byte("test"))), - sdk.AccAddress{}, - 95, - ) - err = vva.Validate() - suite.Require().NoError(err) - ak.SetAccount(ctx, vva) - } - supplyKeeper := tApp.GetSupplyKeeper() - supplyKeeper.MintCoins(ctx, types.IncentiveMacc, sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(1000)))) - keeper := tApp.GetIncentiveKeeper() - suite.app = tApp - suite.ctx = ctx - suite.keeper = keeper - - err := suite.keeper.PayoutClaim(suite.ctx, tc.args.claimOwner, tc.args.collateralType, tc.args.id, tc.args.multiplier) - - if tc.errArgs.expectPass { - suite.Require().NoError(err) - acc := suite.getAccount(tc.args.claimOwner) - suite.Require().Equal(tc.args.expectedAccountBalance, acc.GetCoins()) - mAcc := suite.getModuleAccount(types.IncentiveMacc) - suite.Require().Equal(tc.args.expectedModAccountBalance, mAcc.GetCoins()) - vacc, ok := acc.(*vesting.PeriodicVestingAccount) - if tc.args.expectedVestingAccount { - suite.Require().True(ok) - suite.Require().Equal(tc.args.expectedVestingLength, vacc.VestingPeriods[0].Length) - } else { - suite.Require().False(ok) - } - _, f := suite.keeper.GetClaim(ctx, tc.args.claimOwner, tc.args.collateralType, tc.args.id) - suite.Require().False(f) - } else { - suite.Require().Error(err) - suite.Require().True(strings.Contains(err.Error(), tc.errArgs.contains)) - } +func (suite *KeeperTestSuite) SetupWithAccountState() { + // creates a new app state with 4 funded addresses and 1 module account + tApp := app.NewTestApp() + ctx := tApp.NewContext(true, abci.Header{Height: 1, Time: time.Unix(100, 0)}) + _, addrs := app.GeneratePrivKeyAddressPairs(4) + authGS := app.NewAuthGenState( + addrs, + []sdk.Coins{ + cs(c("ukava", 400)), + cs(c("ukava", 400)), + cs(c("ukava", 400)), + cs(c("ukava", 400)), }) + tApp.InitializeFromGenesisStates( + authGS, + ) + supplyKeeper := tApp.GetSupplyKeeper() + macc := supplyKeeper.GetModuleAccount(ctx, kavadist.ModuleName) + err := supplyKeeper.MintCoins(ctx, macc.GetName(), cs(c("ukava", 600))) + suite.Require().NoError(err) + + // sets addrs[0] to be a periodic vesting account + ak := tApp.GetAccountKeeper() + acc := ak.GetAccount(ctx, addrs[0]) + bacc := auth.NewBaseAccount(acc.GetAddress(), acc.GetCoins(), acc.GetPubKey(), acc.GetAccountNumber(), acc.GetSequence()) + periods := vesting.Periods{ + vesting.Period{Length: int64(1), Amount: cs(c("ukava", 100))}, + vesting.Period{Length: int64(2), Amount: cs(c("ukava", 100))}, + vesting.Period{Length: int64(8), Amount: cs(c("ukava", 100))}, + vesting.Period{Length: int64(5), Amount: cs(c("ukava", 100))}, } + bva, err2 := vesting.NewBaseVestingAccount(bacc, cs(c("ukava", 400)), ctx.BlockTime().Unix()+16) + suite.Require().NoError(err2) + pva := vesting.NewPeriodicVestingAccountRaw(bva, ctx.BlockTime().Unix(), periods) + ak.SetAccount(ctx, pva) + + // sets addrs[2] to be a validator vesting account + acc = ak.GetAccount(ctx, addrs[2]) + bacc = auth.NewBaseAccount(acc.GetAddress(), acc.GetCoins(), acc.GetPubKey(), acc.GetAccountNumber(), acc.GetSequence()) + bva, err2 = vesting.NewBaseVestingAccount(bacc, cs(c("ukava", 400)), ctx.BlockTime().Unix()+16) + suite.Require().NoError(err2) + vva := validatorvesting.NewValidatorVestingAccountRaw(bva, ctx.BlockTime().Unix(), periods, sdk.ConsAddress{}, nil, 90) + ak.SetAccount(ctx, vva) + suite.app = tApp + suite.keeper = tApp.GetIncentiveKeeper() + suite.ctx = ctx + suite.addrs = addrs } diff --git a/x/incentive/keeper/querier.go b/x/incentive/keeper/querier.go index d068311b..915d1380 100644 --- a/x/incentive/keeper/querier.go +++ b/x/incentive/keeper/querier.go @@ -1,6 +1,7 @@ package keeper import ( + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -18,10 +19,6 @@ func NewQuerier(k Keeper) sdk.Querier { return queryGetParams(ctx, req, k) case types.QueryGetClaims: return queryGetClaims(ctx, req, k) - case types.QueryGetRewardPeriods: - return queryGetRewardPeriods(ctx, req, k) - case types.QueryGetClaimPeriods: - return queryGetClaimPeriods(ctx, req, k) default: return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown %s query endpoint", types.ModuleName) } @@ -41,41 +38,30 @@ func queryGetParams(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, e return bz, nil } -// query reward periods in the store -func queryGetRewardPeriods(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { - // Get params - rewardPeriods := k.GetAllRewardPeriods(ctx) - - // Encode results - bz, err := codec.MarshalJSONIndent(k.cdc, rewardPeriods) - if err != nil { - return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) - } - return bz, nil -} - -// query claim periods in the store -func queryGetClaimPeriods(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { - // Get params - claimPeriods := k.GetAllClaimPeriods(ctx) - - // Encode results - bz, err := codec.MarshalJSONIndent(k.cdc, claimPeriods) - if err != nil { - return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) - } - return bz, nil -} - func queryGetClaims(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var requestParams types.QueryClaimsParams err := k.cdc.UnmarshalJSON(req.Data, &requestParams) if err != nil { return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } - claims, _ := k.GetAllClaimsByAddressAndCollateralType(ctx, requestParams.Owner, requestParams.CollateralType) + var claims types.USDXMintingClaims + if len(requestParams.Owner) > 0 { + claim, _ := k.GetClaim(ctx, requestParams.Owner) + claims = append(claims, claim) + } else { + claims = k.GetAllClaims(ctx) + } - bz, err := codec.MarshalJSONIndent(k.cdc, claims) + var paginatedClaims types.USDXMintingClaims + + start, end := client.Paginate(len(claims), requestParams.Page, requestParams.Limit, 100) + if start < 0 || end < 0 { + paginatedClaims = types.USDXMintingClaims{} + } else { + paginatedClaims = claims[start:end] + } + + bz, err := codec.MarshalJSONIndent(k.cdc, paginatedClaims) if err != nil { return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } diff --git a/x/incentive/keeper/querier_test.go b/x/incentive/keeper/querier_test.go deleted file mode 100644 index e5646bc3..00000000 --- a/x/incentive/keeper/querier_test.go +++ /dev/null @@ -1,48 +0,0 @@ -package keeper_test - -import ( - "strings" - - abci "github.com/tendermint/tendermint/abci/types" - - "github.com/kava-labs/kava/x/incentive/keeper" - "github.com/kava-labs/kava/x/incentive/types" -) - -func (suite *KeeperTestSuite) TestQuerier() { - suite.addObjectsToStore() - querier := keeper.NewQuerier(suite.keeper) - bz, err := querier(suite.ctx, []string{types.QueryGetParams}, abci.RequestQuery{}) - suite.Require().NoError(err) - suite.NotNil(bz) - - var p types.Params - suite.Nil(types.ModuleCdc.UnmarshalJSON(bz, &p)) - - claimQueryParams := types.NewQueryClaimsParams(suite.addrs[0], "bnb") - query := abci.RequestQuery{ - Path: strings.Join([]string{"custom", types.QuerierRoute, types.QueryGetClaims}, "/"), - Data: types.ModuleCdc.MustMarshalJSON(claimQueryParams), - } - bz, err = querier(suite.ctx, []string{types.QueryGetClaims}, query) - - var claims types.AugmentedClaims - suite.Nil(types.ModuleCdc.UnmarshalJSON(bz, &claims)) - suite.Equal(1, len(claims)) - suite.Equal(types.AugmentedClaims{ - types.NewAugmentedClaim(types.NewClaim(suite.addrs[0], c("ukava", 1000000), "bnb", 1), true), - }, claims) - - var rp types.RewardPeriods - bz, err = querier(suite.ctx, []string{types.QueryGetRewardPeriods}, abci.RequestQuery{}) - suite.Require().NoError(err) - suite.NotNil(bz) - suite.Nil(types.ModuleCdc.UnmarshalJSON(bz, &rp)) - - var cp types.ClaimPeriods - bz, err = querier(suite.ctx, []string{types.QueryGetClaimPeriods}, abci.RequestQuery{}) - suite.Require().NoError(err) - suite.NotNil(bz) - suite.Nil(types.ModuleCdc.UnmarshalJSON(bz, &cp)) - -} diff --git a/x/incentive/keeper/rewards.go b/x/incentive/keeper/rewards.go index 987b77e1..0e5b27be 100644 --- a/x/incentive/keeper/rewards.go +++ b/x/incentive/keeper/rewards.go @@ -1,118 +1,172 @@ package keeper import ( + "math" "time" - "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" cdptypes "github.com/kava-labs/kava/x/cdp/types" "github.com/kava-labs/kava/x/incentive/types" ) -// HandleRewardPeriodExpiry deletes expired RewardPeriods from the store and creates a ClaimPeriod in the store for each expired RewardPeriod -func (k Keeper) HandleRewardPeriodExpiry(ctx sdk.Context, rp types.RewardPeriod) { - k.CreateUniqueClaimPeriod(ctx, rp.CollateralType, rp.ClaimEnd, rp.ClaimMultipliers) - store := prefix.NewStore(ctx.KVStore(k.key), types.RewardPeriodKeyPrefix) - store.Delete([]byte(rp.CollateralType)) - return -} - -// CreateNewRewardPeriod creates a new reward period from the input reward -func (k Keeper) CreateNewRewardPeriod(ctx sdk.Context, reward types.Reward) { - rp := types.NewRewardPeriodFromReward(reward, ctx.BlockTime()) - k.SetRewardPeriod(ctx, rp) - - ctx.EventManager().EmitEvent( - sdk.NewEvent( - types.EventTypeRewardPeriod, - sdk.NewAttribute(types.AttributeKeyRewardPeriod, rp.String()), - ), - ) -} - -// CreateAndDeleteRewardPeriods creates reward periods for active rewards that don't already have a reward period and deletes reward periods for inactive rewards that currently have a reward period -func (k Keeper) CreateAndDeleteRewardPeriods(ctx sdk.Context) { - params := k.GetParams(ctx) - - for _, r := range params.Rewards { - _, found := k.GetRewardPeriod(ctx, r.CollateralType) - // if governance has made a reward inactive, delete the current period - if found && !r.Active { - k.DeleteRewardPeriod(ctx, r.CollateralType) - } - // if a reward period for an active reward is not found, create one - if !found && r.Active { - k.CreateNewRewardPeriod(ctx, r) - } +// AccumulateRewards updates the rewards accumulated for the input reward period +func (k Keeper) AccumulateRewards(ctx sdk.Context, rewardPeriod types.RewardPeriod) error { + if !rewardPeriod.Active { + k.SetPreviousAccrualTime(ctx, rewardPeriod.CollateralType, ctx.BlockTime()) + return nil } + previousAccrualTime, found := k.GetPreviousAccrualTime(ctx, rewardPeriod.CollateralType) + if !found { + k.SetPreviousAccrualTime(ctx, rewardPeriod.CollateralType, ctx.BlockTime()) + return nil + } + timeElapsed := CalculateTimeElapsed(rewardPeriod, ctx.BlockTime(), previousAccrualTime) + if timeElapsed.IsZero() { + return nil + } + if rewardPeriod.RewardsPerSecond.Amount.IsZero() { + k.SetPreviousAccrualTime(ctx, rewardPeriod.CollateralType, ctx.BlockTime()) + return nil + } + totalPrincipal := k.cdpKeeper.GetTotalPrincipal(ctx, rewardPeriod.CollateralType, types.PrincipalDenom).ToDec() + if totalPrincipal.IsZero() { + k.SetPreviousAccrualTime(ctx, rewardPeriod.CollateralType, ctx.BlockTime()) + return nil + } + newRewards := timeElapsed.Mul(rewardPeriod.RewardsPerSecond.Amount) + cdpFactor, found := k.cdpKeeper.GetInterestFactor(ctx, rewardPeriod.CollateralType) + if !found { + k.SetPreviousAccrualTime(ctx, rewardPeriod.CollateralType, ctx.BlockTime()) + return nil + } + rewardFactor := newRewards.ToDec().Mul(cdpFactor).Quo(totalPrincipal) + + previousRewardFactor, found := k.GetRewardFactor(ctx, rewardPeriod.CollateralType) + if !found { + previousRewardFactor = sdk.ZeroDec() + } + newRewardFactor := previousRewardFactor.Add(rewardFactor) + k.SetRewardFactor(ctx, rewardPeriod.CollateralType, newRewardFactor) + k.SetPreviousAccrualTime(ctx, rewardPeriod.CollateralType, ctx.BlockTime()) + return nil } -// ApplyRewardsToCdps iterates over the reward periods and creates a claim for each -// cdp owner that created usdx with the collateral specified in the reward period. -func (k Keeper) ApplyRewardsToCdps(ctx sdk.Context) { - previousBlockTime, found := k.GetPreviousBlockTime(ctx) +// InitializeClaim creates or updates a claim such that no new rewards are accrued, but any existing rewards are not lost. +// this function should be called after a cdp is created. If a user previously had a cdp, then closed it, they shouldn't +// accrue rewards during the period the cdp was closed. By setting the reward factor to the current global reward factor, +// any unclaimed rewards are preserved, but no new rewards are added. +func (k Keeper) InitializeClaim(ctx sdk.Context, cdp cdptypes.CDP) { + _, found := k.GetRewardPeriod(ctx, cdp.Type) if !found { - previousBlockTime = ctx.BlockTime() - k.SetPreviousBlockTime(ctx, previousBlockTime) + // this collateral type is not incentivized, do nothing return } - - k.IterateRewardPeriods(ctx, func(rp types.RewardPeriod) bool { - expired := false - // the total amount of usdx created with the collateral type being incentivized - totalPrincipal := k.cdpKeeper.GetTotalPrincipal(ctx, rp.CollateralType, types.PrincipalDenom) - // the number of seconds since last payout - timeElapsed := sdk.NewInt(ctx.BlockTime().Unix() - previousBlockTime.Unix()) - if rp.End.Before(ctx.BlockTime()) { - timeElapsed = sdk.NewInt(rp.End.Unix() - previousBlockTime.Unix()) - expired = true - } - - // the amount of rewards to pay (rewardAmount * timeElapsed) - rewardsThisPeriod := rp.Reward.Amount.Mul(timeElapsed) - id := k.GetNextClaimPeriodID(ctx, rp.CollateralType) - k.cdpKeeper.IterateCdpsByCollateralType(ctx, rp.CollateralType, func(cdp cdptypes.CDP) bool { - rewardsShare := sdk.NewDecFromInt(cdp.GetTotalPrincipal().Amount).Quo(sdk.NewDecFromInt(totalPrincipal)) - // sanity check - don't create zero claims - if rewardsShare.IsZero() { - return false - } - rewardsEarned := rewardsShare.Mul(sdk.NewDecFromInt(rewardsThisPeriod)).RoundInt() - k.AddToClaim(ctx, cdp.Owner, rp.CollateralType, id, sdk.NewCoin(types.GovDenom, rewardsEarned)) - return false - }) - if !expired { - return false - } - k.HandleRewardPeriodExpiry(ctx, rp) - return false - }) - - k.SetPreviousBlockTime(ctx, ctx.BlockTime()) -} - -// CreateUniqueClaimPeriod creates a new claim period in the store and updates the highest claim period id -func (k Keeper) CreateUniqueClaimPeriod(ctx sdk.Context, collateralType string, end time.Time, multipliers types.Multipliers) { - id := k.GetNextClaimPeriodID(ctx, collateralType) - claimPeriod := types.NewClaimPeriod(collateralType, id, end, multipliers) - ctx.EventManager().EmitEvent( - sdk.NewEvent( - types.EventTypeClaimPeriod, - sdk.NewAttribute(types.AttributeKeyClaimPeriod, claimPeriod.String()), - ), - ) - k.SetClaimPeriod(ctx, claimPeriod) - k.SetNextClaimPeriodID(ctx, collateralType, id+1) -} - -// AddToClaim adds the amount to an existing claim or creates a new one for that amount -func (k Keeper) AddToClaim(ctx sdk.Context, addr sdk.AccAddress, collateralType string, id uint64, amount sdk.Coin) { - claim, found := k.GetClaim(ctx, addr, collateralType, id) - if found { - claim.Reward = claim.Reward.Add(amount) - } else { - claim = types.NewClaim(addr, amount, collateralType, id) + rewardFactor, found := k.GetRewardFactor(ctx, cdp.Type) + if !found { + rewardFactor = sdk.ZeroDec() + } + claim, found := k.GetClaim(ctx, cdp.Owner) + if !found { // this is the owner's first usdx minting reward claim + claim = types.NewUSDXMintingClaim(cdp.Owner, sdk.NewCoin(types.USDXMintingRewardDenom, sdk.ZeroInt()), types.RewardIndexes{types.NewRewardIndex(cdp.Type, rewardFactor)}) + k.SetClaim(ctx, claim) + return + } + // the owner has an existing usdx minting reward claim + index, hasRewardIndex := claim.HasRewardIndex(cdp.Type) + if !hasRewardIndex { // this is the owner's first usdx minting reward for this collateral type + claim.RewardIndexes = append(claim.RewardIndexes, types.NewRewardIndex(cdp.Type, rewardFactor)) + } else { // the owner has a previous usdx minting reward for this collateral type + claim.RewardIndexes[index] = types.NewRewardIndex(cdp.Type, rewardFactor) } k.SetClaim(ctx, claim) } + +// SynchronizeReward updates the claim object by adding any accumulated rewards and updating the reward index value. +// this should be called before a cdp is modified, immediately after the 'SynchronizeInterest' method is called in the cdp module +func (k Keeper) SynchronizeReward(ctx sdk.Context, cdp cdptypes.CDP) { + _, found := k.GetRewardPeriod(ctx, cdp.Type) + if !found { + // this collateral type is not incentivized, do nothing + return + } + + globalRewardFactor, found := k.GetRewardFactor(ctx, cdp.Type) + if !found { + globalRewardFactor = sdk.ZeroDec() + } + claim, found := k.GetClaim(ctx, cdp.Owner) + if !found { + claim = types.NewUSDXMintingClaim(cdp.Owner, sdk.NewCoin(types.USDXMintingRewardDenom, sdk.ZeroInt()), types.RewardIndexes{types.NewRewardIndex(cdp.Type, globalRewardFactor)}) + k.SetClaim(ctx, claim) + return + } + + // the owner has an existing usdx minting reward claim + index, hasRewardIndex := claim.HasRewardIndex(cdp.Type) + if !hasRewardIndex { // this is the owner's first usdx minting reward for this collateral type + claim.RewardIndexes = append(claim.RewardIndexes, types.NewRewardIndex(cdp.Type, globalRewardFactor)) + k.SetClaim(ctx, claim) + return + } + userRewardFactor := claim.RewardIndexes[index].RewardFactor + rewardsAccumulatedFactor := globalRewardFactor.Sub(userRewardFactor) + if rewardsAccumulatedFactor.IsZero() { + return + } + claim.RewardIndexes[index].RewardFactor = globalRewardFactor + newRewardsAmount := cdp.GetTotalPrincipal().Amount.ToDec().Quo(cdp.InterestFactor).Mul(rewardsAccumulatedFactor).RoundInt() + if newRewardsAmount.IsZero() { + k.SetClaim(ctx, claim) + return + } + newRewardsCoin := sdk.NewCoin(types.USDXMintingRewardDenom, newRewardsAmount) + claim.Reward = claim.Reward.Add(newRewardsCoin) + k.SetClaim(ctx, claim) + return +} + +// ZeroClaim zeroes out the claim object's rewards and returns the updated claim object +func (k Keeper) ZeroClaim(ctx sdk.Context, claim types.USDXMintingClaim) types.USDXMintingClaim { + claim.Reward = sdk.NewCoin(claim.Reward.Denom, sdk.ZeroInt()) + k.SetClaim(ctx, claim) + return claim +} + +// SynchronizeClaim updates the claim object by adding any rewards that have accumulated. +// Returns the updated claim object +func (k Keeper) SynchronizeClaim(ctx sdk.Context, claim types.USDXMintingClaim) (types.USDXMintingClaim, error) { + for _, ri := range claim.RewardIndexes { + cdp, found := k.cdpKeeper.GetCdpByOwnerAndCollateralType(ctx, claim.Owner, ri.CollateralType) + if !found { + // if the cdp for this collateral type has been closed, no updates are needed + continue + } + claim = k.synchronizeRewardAndReturnClaim(ctx, cdp) + } + return claim, nil +} + +// this function assumes a claim already exists, so don't call it if that's not the case +func (k Keeper) synchronizeRewardAndReturnClaim(ctx sdk.Context, cdp cdptypes.CDP) types.USDXMintingClaim { + k.SynchronizeReward(ctx, cdp) + claim, _ := k.GetClaim(ctx, cdp.Owner) + return claim +} + +// CalculateTimeElapsed calculates the number of reward-eligible seconds that have passed since the previous +// time rewards were accrued, taking into account the end time of the reward period +func CalculateTimeElapsed(rewardPeriod types.RewardPeriod, blockTime time.Time, previousAccrualTime time.Time) sdk.Int { + if rewardPeriod.End.Before(blockTime) && + (rewardPeriod.End.Before(previousAccrualTime) || rewardPeriod.End.Equal(previousAccrualTime)) { + return sdk.ZeroInt() + } + if rewardPeriod.End.Before(blockTime) { + return sdk.NewInt(int64(math.RoundToEven( + rewardPeriod.End.Sub(previousAccrualTime).Seconds(), + ))) + } + return sdk.NewInt(int64(math.RoundToEven( + blockTime.Sub(previousAccrualTime).Seconds(), + ))) +} diff --git a/x/incentive/keeper/rewards_test.go b/x/incentive/keeper/rewards_test.go index 49bab5f6..2cad1154 100644 --- a/x/incentive/keeper/rewards_test.go +++ b/x/incentive/keeper/rewards_test.go @@ -1,262 +1,323 @@ package keeper_test import ( + "fmt" + "testing" "time" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" tmtime "github.com/tendermint/tendermint/types/time" "github.com/kava-labs/kava/app" - "github.com/kava-labs/kava/x/cdp" + cdpkeeper "github.com/kava-labs/kava/x/cdp/keeper" + cdptypes "github.com/kava-labs/kava/x/cdp/types" "github.com/kava-labs/kava/x/incentive/types" - "github.com/kava-labs/kava/x/pricefeed" ) -func (suite *KeeperTestSuite) TestExpireRewardPeriod() { - rp := types.NewRewardPeriod("bnb", suite.ctx.BlockTime(), suite.ctx.BlockTime().Add(time.Hour*168), c("ukava", 100000000), suite.ctx.BlockTime().Add(time.Hour*168*2), types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))}) - suite.keeper.SetRewardPeriod(suite.ctx, rp) - suite.keeper.SetNextClaimPeriodID(suite.ctx, "bnb", 1) - suite.NotPanics(func() { - suite.keeper.HandleRewardPeriodExpiry(suite.ctx, rp) - }) - _, found := suite.keeper.GetClaimPeriod(suite.ctx, 1, "bnb") - suite.True(found) -} - -func (suite *KeeperTestSuite) TestAddToClaim() { - rp := types.NewRewardPeriod("bnb", suite.ctx.BlockTime(), suite.ctx.BlockTime().Add(time.Hour*168), c("ukava", 100000000), suite.ctx.BlockTime().Add(time.Hour*168*2), types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))}) - suite.keeper.SetRewardPeriod(suite.ctx, rp) - suite.keeper.SetNextClaimPeriodID(suite.ctx, "bnb", 1) - suite.keeper.HandleRewardPeriodExpiry(suite.ctx, rp) - c1 := types.NewClaim(suite.addrs[0], c("ukava", 1000000), "bnb", 1) - suite.keeper.SetClaim(suite.ctx, c1) - suite.NotPanics(func() { - suite.keeper.AddToClaim(suite.ctx, suite.addrs[0], "bnb", 1, c("ukava", 1000000)) - }) - testC, _ := suite.keeper.GetClaim(suite.ctx, suite.addrs[0], "bnb", 1) - suite.Equal(c("ukava", 2000000), testC.Reward) - - suite.NotPanics(func() { - suite.keeper.AddToClaim(suite.ctx, suite.addrs[0], "xpr", 1, c("ukava", 1000000)) - }) -} - -func (suite *KeeperTestSuite) TestCreateRewardPeriod() { - reward := types.NewReward(true, "bnb", c("ukava", 1000000000), time.Hour*7*24, types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))}, time.Hour*7*24) - suite.NotPanics(func() { - suite.keeper.CreateNewRewardPeriod(suite.ctx, reward) - }) - _, found := suite.keeper.GetRewardPeriod(suite.ctx, "bnb") - suite.True(found) -} - -func (suite *KeeperTestSuite) TestCreateAndDeleteRewardsPeriods() { - reward1 := types.NewReward(true, "bnb", c("ukava", 1000000000), time.Hour*7*24, types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))}, time.Hour*7*24) - reward2 := types.NewReward(false, "xrp", c("ukava", 1000000000), time.Hour*7*24, types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))}, time.Hour*7*24) - reward3 := types.NewReward(false, "btc", c("ukava", 1000000000), time.Hour*7*24, types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))}, time.Hour*7*24) - // add a reward period to the store for a non-active reward - suite.NotPanics(func() { - suite.keeper.CreateNewRewardPeriod(suite.ctx, reward3) - }) - params := types.NewParams(true, types.Rewards{reward1, reward2, reward3}) - suite.keeper.SetParams(suite.ctx, params) - - suite.NotPanics(func() { - suite.keeper.CreateAndDeleteRewardPeriods(suite.ctx) - }) - testCases := []struct { - name string - arg string - expectFound bool - }{ +func (suite *KeeperTestSuite) TestAccumulateRewards() { + type args struct { + ctype string + rewardsPerSecond sdk.Coin + initialTime time.Time + initialTotalPrincipal sdk.Coin + timeElapsed int + expectedRewardFactor sdk.Dec + } + type test struct { + name string + args args + } + testCases := []test{ { - "active reward period", - "bnb", - true, + "7 seconds", + args{ + ctype: "bnb-a", + rewardsPerSecond: c("ukava", 122354), + initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + initialTotalPrincipal: c("usdx", 1000000000000), + timeElapsed: 7, + expectedRewardFactor: d("0.000000856478000000"), + }, }, { - "attempt to add inactive reward period", - "xrp", - false, + "1 day", + args{ + ctype: "bnb-a", + rewardsPerSecond: c("ukava", 122354), + initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + initialTotalPrincipal: c("usdx", 1000000000000), + timeElapsed: 86400, + expectedRewardFactor: d("0.0105713856"), + }, }, { - "remove inactive reward period", - "btc", - false, + "0 seconds", + args{ + ctype: "bnb-a", + rewardsPerSecond: c("ukava", 122354), + initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + initialTotalPrincipal: c("usdx", 1000000000000), + timeElapsed: 0, + expectedRewardFactor: d("0.0"), + }, }, } for _, tc := range testCases { suite.Run(tc.name, func() { - _, found := suite.keeper.GetRewardPeriod(suite.ctx, tc.arg) - if tc.expectFound { - suite.True(found) - } else { - suite.False(found) - } + suite.SetupWithCDPGenState() + suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime) + + // setup cdp state + cdpKeeper := suite.app.GetCDPKeeper() + cdpKeeper.SetTotalPrincipal(suite.ctx, tc.args.ctype, cdptypes.DefaultStableDenom, tc.args.initialTotalPrincipal.Amount) + + // setup incentive state + params := types.NewParams( + types.RewardPeriods{types.NewRewardPeriod(true, tc.args.ctype, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)}, + types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, + tc.args.initialTime.Add(time.Hour*24*365*5), + ) + suite.keeper.SetParams(suite.ctx, params) + suite.keeper.SetPreviousAccrualTime(suite.ctx, tc.args.ctype, tc.args.initialTime) + suite.keeper.SetRewardFactor(suite.ctx, tc.args.ctype, sdk.ZeroDec()) + + updatedBlockTime := suite.ctx.BlockTime().Add(time.Duration(int(time.Second) * tc.args.timeElapsed)) + suite.ctx = suite.ctx.WithBlockTime(updatedBlockTime) + rewardPeriod, found := suite.keeper.GetRewardPeriod(suite.ctx, tc.args.ctype) + suite.Require().True(found) + err := suite.keeper.AccumulateRewards(suite.ctx, rewardPeriod) + suite.Require().NoError(err) + + rewardFactor, found := suite.keeper.GetRewardFactor(suite.ctx, tc.args.ctype) + suite.Require().Equal(tc.args.expectedRewardFactor, rewardFactor) }) } } -func (suite *KeeperTestSuite) TestApplyRewardsToCdps() { - suite.setupCdpChain() // creates a test app with 3 BNB cdps and usdx incentives for bnb - each reward period is one week +func (suite *KeeperTestSuite) TestSyncRewards() { + type args struct { + ctype string + rewardsPerSecond sdk.Coin + initialTime time.Time + initialCollateral sdk.Coin + initialPrincipal sdk.Coin + blockTimes []int + expectedRewardFactor sdk.Dec + expectedRewards sdk.Coin + } + type test struct { + name string + args args + } - // move the context forward by 100 periods - suite.ctx = suite.ctx.WithBlockTime(suite.ctx.BlockTime().Add(time.Second * 100)) - // apply rewards to BNB cdps - suite.NotPanics(func() { - suite.keeper.ApplyRewardsToCdps(suite.ctx) - }) - // each cdp should have a claim - claims := types.Claims{} - suite.keeper.IterateClaims(suite.ctx, func(c types.Claim) (stop bool) { - claims = append(claims, c) - return false - }) - suite.Equal(3, len(claims)) - // there should be no associated claim period, because the reward period has not ended yet - _, found := suite.keeper.GetClaimPeriod(suite.ctx, 1, "bnb-a") - suite.False(found) + testCases := []test{ + { + "10 blocks", + args{ + ctype: "bnb-a", + rewardsPerSecond: c("ukava", 122354), + initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + initialCollateral: c("bnb", 1000000000000), + initialPrincipal: c("usdx", 10000000000), + blockTimes: []int{10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, + expectedRewardFactor: d("0.001223540000000000"), + expectedRewards: c("ukava", 12235400), + }, + }, + { + "10 blocks - long block time", + args{ + ctype: "bnb-a", + rewardsPerSecond: c("ukava", 122354), + initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + initialCollateral: c("bnb", 1000000000000), + initialPrincipal: c("usdx", 10000000000), + blockTimes: []int{86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400}, + expectedRewardFactor: d("10.57138560000000000"), + expectedRewards: c("ukava", 105713856000), + }, + }, + } + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupWithCDPGenState() + suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime) - // move ctx to the reward period expiry and check that the claim period has been created and the next claim period id has increased - suite.ctx = suite.ctx.WithBlockTime(suite.ctx.BlockTime().Add(time.Hour * 24 * 7)) + // setup incentive state + params := types.NewParams( + types.RewardPeriods{types.NewRewardPeriod(true, tc.args.ctype, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)}, + types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, + tc.args.initialTime.Add(time.Hour*24*365*5), + ) + suite.keeper.SetParams(suite.ctx, params) + suite.keeper.SetPreviousAccrualTime(suite.ctx, tc.args.ctype, tc.args.initialTime) + suite.keeper.SetRewardFactor(suite.ctx, tc.args.ctype, sdk.ZeroDec()) - suite.NotPanics(func() { - // apply rewards to cdps - suite.keeper.ApplyRewardsToCdps(suite.ctx) - // delete the old reward period amd create a new one - suite.keeper.CreateAndDeleteRewardPeriods(suite.ctx) - }) - _, found = suite.keeper.GetClaimPeriod(suite.ctx, 1, "bnb-a") - suite.True(found) - testID := suite.keeper.GetNextClaimPeriodID(suite.ctx, "bnb-a") - suite.Equal(uint64(2), testID) + // setup account state + sk := suite.app.GetSupplyKeeper() + sk.MintCoins(suite.ctx, cdptypes.ModuleName, sdk.NewCoins(tc.args.initialCollateral)) + sk.SendCoinsFromModuleToAccount(suite.ctx, cdptypes.ModuleName, suite.addrs[0], sdk.NewCoins(tc.args.initialCollateral)) + + // setup cdp state + cdpKeeper := suite.app.GetCDPKeeper() + err := cdpKeeper.AddCdp(suite.ctx, suite.addrs[0], tc.args.initialCollateral, tc.args.initialPrincipal, tc.args.ctype) + suite.Require().NoError(err) + + claim, found := suite.keeper.GetClaim(suite.ctx, suite.addrs[0]) + suite.Require().True(found) + suite.Require().Equal(sdk.ZeroDec(), claim.RewardIndexes[0].RewardFactor) + + var timeElapsed int + previousBlockTime := suite.ctx.BlockTime() + for _, t := range tc.args.blockTimes { + timeElapsed += t + updatedBlockTime := previousBlockTime.Add(time.Duration(int(time.Second) * t)) + previousBlockTime = updatedBlockTime + blockCtx := suite.ctx.WithBlockTime(updatedBlockTime) + rewardPeriod, found := suite.keeper.GetRewardPeriod(blockCtx, tc.args.ctype) + suite.Require().True(found) + err := suite.keeper.AccumulateRewards(blockCtx, rewardPeriod) + suite.Require().NoError(err) + } + updatedBlockTime := suite.ctx.BlockTime().Add(time.Duration(int(time.Second) * timeElapsed)) + suite.ctx = suite.ctx.WithBlockTime(updatedBlockTime) + cdp, found := cdpKeeper.GetCdpByOwnerAndCollateralType(suite.ctx, suite.addrs[0], tc.args.ctype) + suite.Require().True(found) + suite.Require().NotPanics(func() { + suite.keeper.SynchronizeReward(suite.ctx, cdp) + }) + + rewardFactor, found := suite.keeper.GetRewardFactor(suite.ctx, tc.args.ctype) + suite.Require().Equal(tc.args.expectedRewardFactor, rewardFactor) + + claim, found = suite.keeper.GetClaim(suite.ctx, suite.addrs[0]) + fmt.Println(claim) + suite.Require().True(found) + suite.Require().Equal(tc.args.expectedRewardFactor, claim.RewardIndexes[0].RewardFactor) + suite.Require().Equal(tc.args.expectedRewards, claim.Reward) + }) + } - // move the context forward by 100 periods - suite.ctx = suite.ctx.WithBlockTime(suite.ctx.BlockTime().Add(time.Second * 100)) - // run the begin blocker functions - suite.NotPanics(func() { - suite.keeper.DeleteExpiredClaimsAndClaimPeriods(suite.ctx) - suite.keeper.ApplyRewardsToCdps(suite.ctx) - suite.keeper.CreateAndDeleteRewardPeriods(suite.ctx) - }) - // each cdp should now have two claims - claims = types.Claims{} - suite.keeper.IterateClaims(suite.ctx, func(c types.Claim) (stop bool) { - claims = append(claims, c) - return false - }) - suite.Equal(6, len(claims)) } -func (suite *KeeperTestSuite) setupCdpChain() { - // creates a new test app with bnb as the only asset the pricefeed and cdp modules - // funds three addresses and creates 3 cdps, funded with 100 BNB, 1000 BNB, and 10000 BNB - // each CDP draws 10, 100, and 1000 USDX respectively - // adds usdx incentives for bnb - 1000 KAVA per week with a 1 year time lock +func TestRewardCalculation(t *testing.T) { + // Test Params + ctype := "bnb-a" + initialTime := time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC) + rewardsPerSecond := c("ukava", 122_354) + initialCollateral := c("bnb", 10_000_000_000) + initialPrincipal := c("usdx", 100_000_000) + oneYear := time.Hour * 24 * 365 + rewardPeriod := types.NewRewardPeriod( + true, + ctype, + initialTime, + initialTime.Add(4*oneYear), + rewardsPerSecond, + ) + + // Setup app and module params + _, addrs := app.GeneratePrivKeyAddressPairs(5) + tApp := app.NewTestApp() + ctx := tApp.NewContext(true, abci.Header{Height: 1, Time: initialTime}) + tApp.InitializeFromGenesisStates( + app.NewAuthGenState(addrs[:1], []sdk.Coins{cs(initialCollateral)}), + NewPricefeedGenStateMulti(), + NewCDPGenStateHighInterest(), + NewIncentiveGenState(initialTime, initialTime.Add(oneYear), rewardPeriod), + ) + + // Create a CDP + cdpKeeper := tApp.GetCDPKeeper() + err := cdpKeeper.AddCdp( + ctx, + addrs[0], + initialCollateral, + initialPrincipal, + ctype, + ) + require.NoError(t, err) + + // Calculate expected cdp reward using iteration + + // Use 10 blocks, each a very long 630720s, to total 6307200s or 1/5th of a year + // The cdp stability fee is set to the max value 500%, so this time ensures the debt increases a significant amount (doubles) + // High stability fees increase the chance of catching calculation bugs. + blockTimes := newRepeatingSliceInt(630720, 10) + expectedCDPReward := sdk.ZeroDec() //c(rewardPeriod.RewardsPerSecond.Denom, 0) + for _, bt := range blockTimes { + ctx = ctx.WithBlockTime(ctx.BlockTime().Add(time.Duration(int(time.Second) * bt))) + + // run cdp and incentive begin blockers to update factors + tApp.BeginBlocker(ctx, abci.RequestBeginBlock{}) + + // calculate expected cdp reward + cdpBlockReward, err := calculateCDPBlockReward(ctx, cdpKeeper, addrs[0], ctype, sdk.NewInt(int64(bt)), rewardPeriod) + require.NoError(t, err) + expectedCDPReward = expectedCDPReward.Add(cdpBlockReward) + } + + // calculate cdp reward using factor + cdp, found := cdpKeeper.GetCdpByOwnerAndCollateralType(ctx, addrs[0], ctype) + require.True(t, found) + incentiveKeeper := tApp.GetIncentiveKeeper() + require.NotPanics(t, func() { + incentiveKeeper.SynchronizeReward(ctx, cdp) + }) + claim, found := incentiveKeeper.GetClaim(ctx, addrs[0]) + require.True(t, found) + + // Compare two methods of calculation + relativeError := expectedCDPReward.Sub(claim.Reward.Amount.ToDec()).Quo(expectedCDPReward).Abs() + maxError := d("0.0001") + require.Truef(t, relativeError.LT(maxError), + "percent diff %s > %s , expected: %s, actual %s,", relativeError, maxError, expectedCDPReward, claim.Reward.Amount, + ) +} + +// calculateCDPBlockReward computes the reward that should be distributed to a cdp for the current block. +func calculateCDPBlockReward(ctx sdk.Context, cdpKeeper cdpkeeper.Keeper, owner sdk.AccAddress, ctype string, timeElapsed sdk.Int, rewardPeriod types.RewardPeriod) (sdk.Dec, error) { + // Calculate total rewards to distribute this block + newRewards := timeElapsed.Mul(rewardPeriod.RewardsPerSecond.Amount) + + // Calculate cdp's share of total debt + totalPrincipal := cdpKeeper.GetTotalPrincipal(ctx, ctype, types.PrincipalDenom).ToDec() + // cdpDebt + cdp, found := cdpKeeper.GetCdpByOwnerAndCollateralType(ctx, owner, ctype) + if !found { + return sdk.Dec{}, fmt.Errorf("couldn't find cdp for owner '%s' and collateral type '%s'", owner, ctype) + } + accumulatedInterest := cdpKeeper.CalculateNewInterest(ctx, cdp) + cdpDebt := cdp.Principal.Add(cdp.AccumulatedFees).Add(accumulatedInterest).Amount + + // Calculate cdp's reward + return newRewards.Mul(cdpDebt).ToDec().Quo(totalPrincipal), nil +} + +func (suite *KeeperTestSuite) SetupWithCDPGenState() { tApp := app.NewTestApp() ctx := tApp.NewContext(true, abci.Header{Height: 1, Time: tmtime.Now()}) - // need pricefeed and cdp gen state with one collateral - pricefeedGS := pricefeed.GenesisState{ - Params: pricefeed.Params{ - Markets: []pricefeed.Market{ - {MarketID: "bnb:usd", BaseAsset: "bnb", QuoteAsset: "usd", Oracles: []sdk.AccAddress{}, Active: true}, - }, - }, - PostedPrices: []pricefeed.PostedPrice{ - { - MarketID: "bnb:usd", - OracleAddress: sdk.AccAddress{}, - Price: d("12.29"), - Expiry: time.Now().Add(100000 * time.Hour), - }, - }, - } - // need incentive params for one collateral - cdpGS := cdp.GenesisState{ - Params: cdp.Params{ - GlobalDebtLimit: sdk.NewInt64Coin("usdx", 1000000000000), - SurplusAuctionThreshold: cdp.DefaultSurplusThreshold, - SurplusAuctionLot: cdp.DefaultSurplusLot, - DebtAuctionThreshold: cdp.DefaultDebtThreshold, - DebtAuctionLot: cdp.DefaultDebtLot, - SavingsDistributionFrequency: cdp.DefaultSavingsDistributionFrequency, - CollateralParams: cdp.CollateralParams{ - { - Denom: "bnb", - Type: "bnb-a", - LiquidationRatio: sdk.MustNewDecFromStr("2.0"), - DebtLimit: sdk.NewInt64Coin("usdx", 1000000000000), - StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), // %5 apr - LiquidationPenalty: d("0.05"), - AuctionSize: i(10000000000), - Prefix: 0x20, - SpotMarketID: "bnb:usd", - LiquidationMarketID: "bnb:usd", - ConversionFactor: i(8), - }, - }, - DebtParam: cdp.DebtParam{ - Denom: "usdx", - ReferenceAsset: "usd", - ConversionFactor: i(6), - DebtFloor: i(10000000), - SavingsRate: d("0.95"), - }, - }, - StartingCdpID: cdp.DefaultCdpStartingID, - DebtDenom: cdp.DefaultDebtDenom, - GovDenom: cdp.DefaultGovDenom, - CDPs: cdp.CDPs{}, - PreviousDistributionTime: cdp.DefaultPreviousDistributionTime, - } - incentiveGS := types.NewGenesisState( - types.NewParams( - true, types.Rewards{types.NewReward(true, "bnb-a", c("ukava", 1000000000), time.Hour*7*24, types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))}, time.Hour*7*24)}, - ), - types.DefaultPreviousBlockTime, - types.RewardPeriods{types.NewRewardPeriod("bnb-a", ctx.BlockTime(), ctx.BlockTime().Add(time.Hour*7*24), c("ukava", 1000), ctx.BlockTime().Add(time.Hour*7*24*2), types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))})}, - types.ClaimPeriods{}, - types.Claims{}, - types.GenesisClaimPeriodIDs{}) - pricefeedAppGs := app.GenesisState{pricefeed.ModuleName: pricefeed.ModuleCdc.MustMarshalJSON(pricefeedGS)} - cdpAppGs := app.GenesisState{cdp.ModuleName: cdp.ModuleCdc.MustMarshalJSON(cdpGS)} - incentiveAppGs := app.GenesisState{types.ModuleName: types.ModuleCdc.MustMarshalJSON(incentiveGS)} - _, addrs := app.GeneratePrivKeyAddressPairs(3) - authGS := app.NewAuthGenState( - addrs[0:3], - []sdk.Coins{ - cs(c("bnb", 10000000000)), - cs(c("bnb", 100000000000)), - cs(c("bnb", 1000000000000)), - }) tApp.InitializeFromGenesisStates( - authGS, - pricefeedAppGs, - incentiveAppGs, - cdpAppGs, + NewPricefeedGenStateMulti(), + NewCDPGenStateMulti(), ) + _, addrs := app.GeneratePrivKeyAddressPairs(5) + keeper := tApp.GetIncentiveKeeper() suite.app = tApp - suite.keeper = tApp.GetIncentiveKeeper() suite.ctx = ctx - // create 3 cdps - cdpKeeper := tApp.GetCDPKeeper() - err := cdpKeeper.AddCdp(suite.ctx, addrs[0], c("bnb", 10000000000), c("usdx", 10000000), "bnb-a") - suite.Require().NoError(err) - err = cdpKeeper.AddCdp(suite.ctx, addrs[1], c("bnb", 100000000000), c("usdx", 100000000), "bnb-a") - suite.Require().NoError(err) - err = cdpKeeper.AddCdp(suite.ctx, addrs[2], c("bnb", 1000000000000), c("usdx", 1000000000), "bnb-a") - suite.Require().NoError(err) - // total usd is 1110 - - // set the previous block time - suite.keeper.SetPreviousBlockTime(suite.ctx, suite.ctx.BlockTime()) + suite.keeper = keeper + suite.addrs = addrs } -// Avoid cluttering test cases with long function names -func i(in int64) sdk.Int { return sdk.NewInt(in) } -func d(str string) sdk.Dec { return sdk.MustNewDecFromStr(str) } -func c(denom string, amount int64) sdk.Coin { return sdk.NewInt64Coin(denom, amount) } -func cs(coins ...sdk.Coin) sdk.Coins { return sdk.NewCoins(coins...) } +// newRepeatingSliceInt creates a slice of the specified length containing a single repeating element. +func newRepeatingSliceInt(element int, length int) []int { + slice := make([]int, length) + for i := 0; i < length; i++ { + slice[i] = element + } + return slice +} diff --git a/x/incentive/simulation/decoder.go b/x/incentive/simulation/decoder.go index 9263de22..89665073 100644 --- a/x/incentive/simulation/decoder.go +++ b/x/incentive/simulation/decoder.go @@ -2,11 +2,11 @@ package simulation import ( "bytes" - "encoding/binary" "fmt" "time" "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/tendermint/tendermint/libs/kv" @@ -16,35 +16,25 @@ import ( // DecodeStore unmarshals the KVPair's Value to the module's corresponding type func DecodeStore(cdc *codec.Codec, kvA, kvB kv.Pair) string { switch { - case bytes.Equal(kvA.Key[:1], types.RewardPeriodKeyPrefix): - var rewardPeriodA, rewardPeriodB types.RewardPeriod - cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &rewardPeriodA) - cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &rewardPeriodB) - return fmt.Sprintf("%v\n%v", rewardPeriodA, rewardPeriodB) - - case bytes.Equal(kvA.Key[:1], types.ClaimPeriodKeyPrefix): - var claimPeriodA, claimPeriodB types.ClaimPeriod - cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &claimPeriodA) - cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &claimPeriodB) - return fmt.Sprintf("%v\n%v", claimPeriodA, claimPeriodB) case bytes.Equal(kvA.Key[:1], types.ClaimKeyPrefix): - var claimA, claimB types.Claim - cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &claimA) - cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &claimB) + var claimA, claimB types.USDXMintingClaim + cdc.MustUnmarshalBinaryBare(kvA.Value, &claimA) + cdc.MustUnmarshalBinaryBare(kvB.Value, &claimB) return fmt.Sprintf("%v\n%v", claimA, claimB) - case bytes.Equal(kvA.Key[:1], types.NextClaimPeriodIDPrefix): - claimPeriodIDA := binary.BigEndian.Uint64(kvA.Value) - claimPeriodIDB := binary.BigEndian.Uint64(kvB.Value) - return fmt.Sprintf("%d\n%d", claimPeriodIDA, claimPeriodIDB) - - case bytes.Equal(kvA.Key[:1], types.PreviousBlockTimeKey): + case bytes.Equal(kvA.Key[:1], types.BlockTimeKey): var timeA, timeB time.Time - cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &timeA) - cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &timeB) + cdc.MustUnmarshalBinaryBare(kvA.Value, &timeA) + cdc.MustUnmarshalBinaryBare(kvB.Value, &timeB) return fmt.Sprintf("%s\n%s", timeA, timeB) + case bytes.Equal(kvA.Key[:1], types.RewardFactorKey): + var factorA, factorB sdk.Dec + cdc.MustUnmarshalBinaryBare(kvA.Value, &factorA) + cdc.MustUnmarshalBinaryBare(kvB.Value, &factorB) + return fmt.Sprintf("%s\n%s", factorA, factorB) + default: panic(fmt.Sprintf("invalid %s key prefix %X", types.ModuleName, kvA.Key[:1])) } diff --git a/x/incentive/simulation/decoder_test.go b/x/incentive/simulation/decoder_test.go index d0acb785..7ce646bf 100644 --- a/x/incentive/simulation/decoder_test.go +++ b/x/incentive/simulation/decoder_test.go @@ -24,21 +24,15 @@ func makeTestCodec() (cdc *codec.Codec) { func TestDecodeDistributionStore(t *testing.T) { cdc := makeTestCodec() - - // Set up RewardPeriod, ClaimPeriod, Claim, and previous block time - rewardPeriod := types.NewRewardPeriod("btc", time.Now().UTC(), time.Now().Add(time.Hour*1).UTC(), - sdk.NewCoin("ukava", sdk.NewInt(10000000000)), time.Now().Add(time.Hour*2).UTC(), types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33"))}) - claimPeriod := types.NewClaimPeriod("btc", 1, time.Now().Add(time.Hour*24).UTC(), types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33"))}) addr, _ := sdk.AccAddressFromBech32("kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw") - claim := types.NewClaim(addr, sdk.NewCoin("ukava", sdk.NewInt(1000000)), "bnb", 1) + claim := types.NewUSDXMintingClaim(addr, sdk.NewCoin("ukava", sdk.NewInt(1000000)), types.RewardIndexes{types.NewRewardIndex("bnb-a", sdk.ZeroDec())}) prevBlockTime := time.Now().Add(time.Hour * -1).UTC() + factor := sdk.ZeroDec() kvPairs := kv.Pairs{ - kv.Pair{Key: types.RewardPeriodKeyPrefix, Value: cdc.MustMarshalBinaryLengthPrefixed(&rewardPeriod)}, - kv.Pair{Key: types.ClaimPeriodKeyPrefix, Value: cdc.MustMarshalBinaryLengthPrefixed(&claimPeriod)}, - kv.Pair{Key: types.ClaimKeyPrefix, Value: cdc.MustMarshalBinaryLengthPrefixed(&claim)}, - kv.Pair{Key: types.NextClaimPeriodIDPrefix, Value: sdk.Uint64ToBigEndian(10)}, - kv.Pair{Key: []byte(types.PreviousBlockTimeKey), Value: cdc.MustMarshalBinaryLengthPrefixed(prevBlockTime)}, + kv.Pair{Key: types.ClaimKeyPrefix, Value: cdc.MustMarshalBinaryBare(claim)}, + kv.Pair{Key: []byte(types.BlockTimeKey), Value: cdc.MustMarshalBinaryBare(prevBlockTime)}, + kv.Pair{Key: []byte(types.RewardFactorKey), Value: cdc.MustMarshalBinaryBare(factor)}, kv.Pair{Key: []byte{0x99}, Value: []byte{0x99}}, } @@ -46,11 +40,9 @@ func TestDecodeDistributionStore(t *testing.T) { name string expectedLog string }{ - {"RewardPeriod", fmt.Sprintf("%v\n%v", rewardPeriod, rewardPeriod)}, - {"ClaimPeriod", fmt.Sprintf("%v\n%v", claimPeriod, claimPeriod)}, {"Claim", fmt.Sprintf("%v\n%v", claim, claim)}, - {"NextClaimPeriodID", "10\n10"}, {"PreviousBlockTime", fmt.Sprintf("%v\n%v", prevBlockTime, prevBlockTime)}, + {"RewardFactor", fmt.Sprintf("%v\n%v", factor, factor)}, {"other", ""}, } for i, tt := range tests { diff --git a/x/incentive/simulation/genesis.go b/x/incentive/simulation/genesis.go index 37bb2fb8..c3700e0a 100644 --- a/x/incentive/simulation/genesis.go +++ b/x/incentive/simulation/genesis.go @@ -2,15 +2,11 @@ package simulation import ( "fmt" - "math/rand" - "time" "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/simulation" - "github.com/kava-labs/kava/x/cdp" "github.com/kava-labs/kava/x/incentive/types" ) @@ -23,115 +19,9 @@ var ( // RandomizedGenState generates a random GenesisState for incentive module func RandomizedGenState(simState *module.SimulationState) { - // Get collateral asset denoms from existing CDP genesis state and pass to incentive params - var cdpGenesis cdp.GenesisState - simState.Cdc.MustUnmarshalJSON(simState.GenState[cdp.ModuleName], &cdpGenesis) - if len(CollateralDenoms) == 0 { - for _, collateral := range cdpGenesis.Params.CollateralParams { - CollateralDenoms = append(CollateralDenoms, collateral.Type) - } - } - - params := genParams(simState.Rand) - - // Generate random reward and claim periods - rewardPeriods := genRewardPeriods(simState.Rand, simState.GenTimestamp, params.Rewards) - claimPeriods := genClaimPeriods(rewardPeriods) - claimPeriodIDs := genNextClaimPeriodIds(claimPeriods) - // New genesis state holds valid, linked reward periods, claim periods, and claim period IDs - incentiveGenesis := types.NewGenesisState(params, types.DefaultPreviousBlockTime, - rewardPeriods, claimPeriods, types.Claims{}, claimPeriodIDs) - if err := incentiveGenesis.Validate(); err != nil { - panic(err) - } + incentiveGenesis := types.DefaultGenesisState() fmt.Printf("Selected randomly generated %s parameters:\n%s\n", types.ModuleName, codec.MustMarshalJSONIndent(simState.Cdc, incentiveGenesis)) simState.GenState[types.ModuleName] = simState.Cdc.MustMarshalJSON(incentiveGenesis) } - -// genParams generates random rewards and is active by default -func genParams(r *rand.Rand) types.Params { - params := types.NewParams(true, genRewards(r)) - if err := params.Validate(); err != nil { - panic(err) - } - return params -} - -// genRewards generates rewards for each specified collateral type -func genRewards(r *rand.Rand) types.Rewards { - rewards := make(types.Rewards, len(CollateralDenoms)) - for i, denom := range CollateralDenoms { - active := true - // total reward is in range (half max total reward, max total reward) - amount := simulation.RandIntBetween(r, int(MaxTotalAssetReward.Int64()/2), int(MaxTotalAssetReward.Int64())) - totalRewards := sdk.NewInt64Coin(RewardDenom, int64(amount)) - // generate a random number of months for lockups - numMonthsSmall := simulation.RandIntBetween(r, 0, 6) - numMonthsLarge := simulation.RandIntBetween(r, 7, 12) - multiplierSmall := types.NewMultiplier(types.Small, int64(numMonthsSmall), sdk.MustNewDecFromStr("0.33")) - multiplierLarge := types.NewMultiplier(types.Large, int64(numMonthsLarge), sdk.MustNewDecFromStr("1.0")) - - duration := time.Duration(time.Hour * time.Duration(simulation.RandIntBetween(r, 1, 48))) - claimDuration := time.Hour * time.Duration(simulation.RandIntBetween(r, 1, 48)) // twice as long as duration - rewards[i] = types.NewReward(active, denom, totalRewards, duration, types.Multipliers{multiplierSmall, multiplierLarge}, claimDuration) - } - return rewards -} - -// genRewardPeriods generates chronological reward periods for each given reward type -func genRewardPeriods(r *rand.Rand, timestamp time.Time, rewards types.Rewards) types.RewardPeriods { - rewardPeriods := make(types.RewardPeriods, len(rewards)) - rewardPeriodStart := timestamp - - for i, reward := range rewards { - // Set up reward period parameters - start := rewardPeriodStart - end := start.Add(reward.Duration).UTC() - baseRewardAmount := reward.AvailableRewards.Amount.Quo(sdk.NewInt(100)) // base period reward is 1/100 total reward - // Earlier periods have larger rewards - amount := sdk.NewCoin("ukava", baseRewardAmount.Mul(sdk.NewInt(int64(i)))) - claimEnd := end.Add(reward.ClaimDuration) - claimMultipliers := reward.ClaimMultipliers - // Create reward period and append to array - rewardPeriods[i] = types.NewRewardPeriod(reward.CollateralType, start, end, amount, claimEnd, claimMultipliers) - // Update start time of next reward period - rewardPeriodStart = end - } - return rewardPeriods -} - -// genClaimPeriods loads valid claim periods for an array of reward periods -func genClaimPeriods(rewardPeriods types.RewardPeriods) types.ClaimPeriods { - denomRewardPeriodsCount := make(map[string]uint64) - claimPeriods := make(types.ClaimPeriods, len(rewardPeriods)) - for i, rewardPeriod := range rewardPeriods { - // Increment reward period count for this denom (this is our claim period's ID) - denom := rewardPeriod.CollateralType - numbRewardPeriods := denomRewardPeriodsCount[denom] + 1 - denomRewardPeriodsCount[denom] = numbRewardPeriods - // Set end and timelock from the associated reward period - end := rewardPeriod.ClaimEnd - claimMultipliers := rewardPeriod.ClaimMultipliers - // Create the new claim period for this reward period - claimPeriods[i] = types.NewClaimPeriod(denom, numbRewardPeriods, end, claimMultipliers) - } - return claimPeriods -} - -// genNextClaimPeriodIds returns an array of the most recent claim period IDs for each denom -func genNextClaimPeriodIds(cps types.ClaimPeriods) types.GenesisClaimPeriodIDs { - // Build a map of the most recent claim periods by denom - mostRecentClaimPeriodByDenom := make(map[string]uint64) - var claimPeriodIDs types.GenesisClaimPeriodIDs - for _, cp := range cps { - if cp.ID <= mostRecentClaimPeriodByDenom[cp.CollateralType] { - continue - } - claimPeriodIDs = append(claimPeriodIDs, types.GenesisClaimPeriodID{CollateralType: cp.CollateralType, ID: cp.ID}) - mostRecentClaimPeriodByDenom[cp.CollateralType] = cp.ID - - } - return claimPeriodIDs -} diff --git a/x/incentive/simulation/operations.go b/x/incentive/simulation/operations.go index 39627f77..9a5db04e 100644 --- a/x/incentive/simulation/operations.go +++ b/x/incentive/simulation/operations.go @@ -1,21 +1,17 @@ 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" - "github.com/cosmos/cosmos-sdk/x/auth/vesting" "github.com/cosmos/cosmos-sdk/x/simulation" appparams "github.com/kava-labs/kava/app/params" "github.com/kava-labs/kava/x/incentive/keeper" "github.com/kava-labs/kava/x/incentive/types" - "github.com/kava-labs/kava/x/kavadist" ) // Simulation operation weights constants @@ -49,100 +45,7 @@ func SimulateMsgClaimReward(ak auth.AccountKeeper, sk types.SupplyKeeper, k keep r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, ) (simulation.OperationMsg, []simulation.FutureOperation, error) { - // Load only account types that can claim rewards - validAccounts := make(map[string]bool) - for _, acc := range accs { - account := ak.GetAccount(ctx, acc.Address) - switch account.(type) { - case *vesting.PeriodicVestingAccount, *auth.BaseAccount: // Valid: BaseAccount, PeriodicVestingAccount - validAccounts[account.GetAddress().String()] = true - default: // Invalid: ValidatorVestingAccount, DelayedVestingAccount, ContinuousVestingAccount - break - } - } - - // Load open claims and shuffle them to randomize - openClaims := types.Claims{} - k.IterateClaims(ctx, func(claim types.Claim) bool { - openClaims = append(openClaims, claim) - return false - }) - r.Shuffle(len(openClaims), func(i, j int) { - openClaims[i], openClaims[j] = openClaims[j], openClaims[i] - }) - - kavadistMacc := sk.GetModuleAccount(ctx, kavadist.KavaDistMacc) - kavadistBalance := kavadistMacc.SpendableCoins(ctx.BlockTime()) - - // Find address that has a claim of the same reward denom, then confirm it's distributable - claimer, claim, found := findValidAccountClaimPair(accs, openClaims, func(acc simulation.Account, claim types.Claim) bool { - if validAccounts[acc.Address.String()] { // Address must be valid type - if claim.Owner.Equals(acc.Address) { // Account must be claim owner - allClaims, found := k.GetActiveClaimsByAddressAndCollateralType(ctx, claim.Owner, claim.CollateralType) - if found { // found should always be true - var rewards sdk.Coins - for _, individualClaim := range allClaims { - rewards = rewards.Add(individualClaim.Reward) - } - if rewards.AmountOf(claim.Reward.Denom).IsPositive() { // Can't distribute 0 coins - // Validate that kavadist module has enough coins to distribute rewards - if kavadistBalance.AmountOf(claim.Reward.Denom).GTE(rewards.AmountOf(claim.Reward.Denom)) { - return true - } - } - } - } - } - return false - }) - if !found { - return simulation.NewOperationMsgBasic(types.ModuleName, - "no-operation (no accounts currently have fulfillable claims)", "", false, nil), nil, nil - } - - claimerAcc := ak.GetAccount(ctx, claimer.Address) - if claimerAcc == nil { - return simulation.NoOpMsg(types.ModuleName), nil, fmt.Errorf("couldn't find account %s", claimer.Address) - } - - multiplierName := types.Small - - if simulation.RandIntBetween(r, 0, 1) == 0 { - multiplierName = types.Large - } - - msg := types.NewMsgClaimReward(claimer.Address, claim.CollateralType, string(multiplierName)) - - tx := helpers.GenTx( - []sdk.Msg{msg}, - sdk.NewCoins(), - helpers.DefaultGenTxGas, - chainID, - []uint64{claimerAcc.GetAccountNumber()}, - []uint64{claimerAcc.GetSequence()}, - claimer.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 + return simulation.NewOperationMsgBasic(types.ModuleName, + "no-operation (no accounts currently have fulfillable claims)", "", false, nil), nil, nil } } - -// findValidAccountClaimPair finds an account and reward claim for which the callback func returns true -func findValidAccountClaimPair(accounts []simulation.Account, claims types.Claims, - cb func(simulation.Account, types.Claim) bool) (simulation.Account, types.Claim, bool) { - for _, claim := range claims { - for _, acc := range accounts { - if isValid := cb(acc, claim); isValid { - return acc, claim, true - } - } - } - return simulation.Account{}, types.Claim{}, false -} diff --git a/x/incentive/simulation/params.go b/x/incentive/simulation/params.go index 19cf0e2a..77007be8 100644 --- a/x/incentive/simulation/params.go +++ b/x/incentive/simulation/params.go @@ -1,12 +1,9 @@ package simulation import ( - "fmt" "math/rand" "github.com/cosmos/cosmos-sdk/x/simulation" - - "github.com/kava-labs/kava/x/incentive/types" ) const ( @@ -23,16 +20,5 @@ func genActive(r *rand.Rand) bool { // ParamChanges defines the parameters that can be modified by param change proposals func ParamChanges(r *rand.Rand) []simulation.ParamChange { - return []simulation.ParamChange{ - simulation.NewSimParamChange(types.ModuleName, keyActive, - func(r *rand.Rand) string { - return fmt.Sprintf("\"%t\"", genActive(r)) - }, - ), - simulation.NewSimParamChange(types.ModuleName, keyRewards, - func(r *rand.Rand) string { - return fmt.Sprintf("\"%v\"", genRewards(r)) - }, - ), - } + return []simulation.ParamChange{} } diff --git a/x/incentive/types/claims.go b/x/incentive/types/claims.go new file mode 100644 index 00000000..3ff9e140 --- /dev/null +++ b/x/incentive/types/claims.go @@ -0,0 +1,112 @@ +package types + +import ( + "errors" + "fmt" + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// USDXMintingClaim stores the usdx mintng rewards that can be claimed by owner +type USDXMintingClaim struct { + Owner sdk.AccAddress `json:"owner" yaml:"owner"` + Reward sdk.Coin `json:"reward" yaml:"reward"` + RewardIndexes RewardIndexes `json:"reward_indexes" yaml:"reward_indexes"` +} + +// NewUSDXMintingClaim returns a new USDXMintingClaim +func NewUSDXMintingClaim(owner sdk.AccAddress, reward sdk.Coin, rewardIndexes RewardIndexes) USDXMintingClaim { + return USDXMintingClaim{ + Owner: owner, + Reward: reward, + RewardIndexes: rewardIndexes, + } +} + +// Validate performs a basic check of a Claim fields. +func (c USDXMintingClaim) Validate() error { + if c.Owner.Empty() { + return errors.New("claim owner cannot be empty") + } + if !c.Reward.IsValid() { + return fmt.Errorf("invalid reward amount: %s", c.Reward) + } + return c.RewardIndexes.Validate() +} + +// String implements fmt.Stringer +func (c USDXMintingClaim) String() string { + return fmt.Sprintf(`Claim: + Owner: %s, + Reward: %s, + Reward Indexes: %s, + `, c.Owner, c.Reward, c.RewardIndexes) +} + +// HasRewardIndex check if a claim has a reward index for the input collateral type +func (c USDXMintingClaim) HasRewardIndex(collateralType string) (int64, bool) { + for index, ri := range c.RewardIndexes { + if ri.CollateralType == collateralType { + return int64(index), true + } + } + return 0, false +} + +// USDXMintingClaims array of USDXMintingClaim +type USDXMintingClaims []USDXMintingClaim + +// Validate checks if all the claims are valid and there are no duplicated +// entries. +func (cs USDXMintingClaims) Validate() error { + for _, c := range cs { + if err := c.Validate(); err != nil { + return err + } + } + + return nil +} + +// RewardIndex stores reward accumulation information +type RewardIndex struct { + CollateralType string `json:"collateral_type" yaml:"collateral_type"` + RewardFactor sdk.Dec `json:"reward_factor" yaml:"reward_factor"` +} + +// NewRewardIndex returns a new RewardIndex +func NewRewardIndex(collateralType string, factor sdk.Dec) RewardIndex { + return RewardIndex{ + CollateralType: collateralType, + RewardFactor: factor, + } +} + +func (ri RewardIndex) String() string { + return fmt.Sprintf(`Collateral Type: %s, RewardFactor: %s`, ri.CollateralType, ri.RewardFactor) +} + +// Validate validates reward index +func (ri RewardIndex) Validate() error { + if ri.RewardFactor.IsNegative() { + return fmt.Errorf("reward factor value should be positive, is %s for %s", ri.RewardFactor, ri.CollateralType) + } + if strings.TrimSpace(ri.CollateralType) == "" { + return fmt.Errorf("collateral type should not be empty") + } + return nil +} + +// RewardIndexes slice of RewardIndex +type RewardIndexes []RewardIndex + +// Validate validation for reward indexes +func (ris RewardIndexes) Validate() error { + for _, ri := range ris { + if err := ri.Validate(); err != nil { + return err + } + } + return nil +} diff --git a/x/incentive/types/claims_test.go b/x/incentive/types/claims_test.go new file mode 100644 index 00000000..5d6cd9ab --- /dev/null +++ b/x/incentive/types/claims_test.go @@ -0,0 +1,66 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/tendermint/tendermint/crypto" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func TestClaimsValidate(t *testing.T) { + owner := sdk.AccAddress(crypto.AddressHash([]byte("KavaTestUser1"))) + + testCases := []struct { + msg string + claims USDXMintingClaims + expPass bool + }{ + { + "valid", + USDXMintingClaims{ + NewUSDXMintingClaim(owner, sdk.NewCoin("bnb", sdk.OneInt()), RewardIndexes{NewRewardIndex("bnb-a", sdk.ZeroDec())}), + }, + true, + }, + { + "invalid owner", + USDXMintingClaims{ + {Owner: nil}, + }, + false, + }, + { + "invalid reward", + USDXMintingClaims{ + { + Owner: owner, + Reward: sdk.Coin{Denom: "", Amount: sdk.ZeroInt()}, + }, + }, + false, + }, + { + "invalid collateral type", + USDXMintingClaims{ + { + Owner: owner, + Reward: sdk.NewCoin("bnb", sdk.OneInt()), + RewardIndexes: []RewardIndex{{"", sdk.ZeroDec()}}, + }, + }, + false, + }, + } + + for _, tc := range testCases { + err := tc.claims.Validate() + if tc.expPass { + require.NoError(t, err, tc.msg) + } else { + require.Error(t, err, tc.msg) + } + } +} diff --git a/x/incentive/types/codec.go b/x/incentive/types/codec.go index 31f066e0..262197e4 100644 --- a/x/incentive/types/codec.go +++ b/x/incentive/types/codec.go @@ -14,9 +14,5 @@ func init() { // RegisterCodec registers the necessary types for incentive module func RegisterCodec(cdc *codec.Codec) { - cdc.RegisterConcrete(MsgClaimReward{}, "incentive/MsgClaimReward", nil) - cdc.RegisterConcrete(GenesisClaimPeriodID{}, "incentive/GenesisClaimPeriodID", nil) - cdc.RegisterConcrete(RewardPeriod{}, "incentive/RewardPeriod", nil) - cdc.RegisterConcrete(ClaimPeriod{}, "incentive/ClaimPeriod", nil) - cdc.RegisterConcrete(Claim{}, "incentive/Claim", nil) + cdc.RegisterConcrete(MsgClaimUSDXMintingReward{}, "incentive/MsgClaimUSDXMintingReward", nil) } diff --git a/x/incentive/types/errors.go b/x/incentive/types/errors.go index 2ce76d02..1a337e73 100644 --- a/x/incentive/types/errors.go +++ b/x/incentive/types/errors.go @@ -9,11 +9,12 @@ import ( // Incentive module errors var ( ErrClaimNotFound = sdkerrors.Register(ModuleName, 2, "no claim with input id found for owner and collateral type") - ErrClaimPeriodNotFound = sdkerrors.Register(ModuleName, 3, "no claim period found for id and collateral type") + ErrRewardPeriodNotFound = sdkerrors.Register(ModuleName, 3, "no reward period found for collateral type") ErrInvalidAccountType = sdkerrors.Register(ModuleName, 4, "account type not supported") ErrNoClaimsFound = sdkerrors.Register(ModuleName, 5, "no claims with collateral type found for address") ErrInsufficientModAccountBalance = sdkerrors.Register(ModuleName, 6, "module account has insufficient balance to pay claim") ErrAccountNotFound = sdkerrors.Register(ModuleName, 7, "account not found") ErrInvalidMultiplier = sdkerrors.Register(ModuleName, 8, "invalid rewards multiplier") ErrZeroClaim = sdkerrors.Register(ModuleName, 9, "cannot claim - claim amount rounds to zero") + ErrClaimExpired = sdkerrors.Register(ModuleName, 10, "claim has expired") ) diff --git a/x/incentive/types/expected_keepers.go b/x/incentive/types/expected_keepers.go index b0c887ad..abc43673 100644 --- a/x/incentive/types/expected_keepers.go +++ b/x/incentive/types/expected_keepers.go @@ -17,8 +17,9 @@ type SupplyKeeper interface { // CdpKeeper defines the expected cdp keeper for interacting with cdps type CdpKeeper interface { - IterateCdpsByCollateralType(ctx sdk.Context, collateralType string, cb func(cdp cdptypes.CDP) (stop bool)) GetTotalPrincipal(ctx sdk.Context, collateralType string, principalDenom string) (total sdk.Int) + GetCdpByOwnerAndCollateralType(ctx sdk.Context, owner sdk.AccAddress, collateralType string) (cdptypes.CDP, bool) + GetInterestFactor(ctx sdk.Context, collateralType string) (sdk.Dec, bool) } // AccountKeeper defines the expected keeper interface for interacting with account @@ -26,3 +27,9 @@ type AccountKeeper interface { GetAccount(ctx sdk.Context, addr sdk.AccAddress) authexported.Account SetAccount(ctx sdk.Context, acc authexported.Account) } + +// CDPHooks event hooks for other keepers to run code in response to CDP modifications +type CDPHooks interface { + AfterCDPCreated(ctx sdk.Context, cdp cdptypes.CDP) + BeforeCDPModified(ctx sdk.Context, cdp cdptypes.CDP) +} diff --git a/x/incentive/types/genesis.go b/x/incentive/types/genesis.go index f4824603..b64051d7 100644 --- a/x/incentive/types/genesis.go +++ b/x/incentive/types/genesis.go @@ -2,83 +2,34 @@ package types import ( "bytes" - "errors" "fmt" - "strings" "time" + + sdk "github.com/cosmos/cosmos-sdk/types" ) -// GenesisClaimPeriodID stores the next claim id and its corresponding collateral type -type GenesisClaimPeriodID struct { - CollateralType string `json:"collateral_type" yaml:"collateral_type"` - ID uint64 `json:"id" yaml:"id"` -} - -// Validate performs a basic check of a GenesisClaimPeriodID fields. -func (gcp GenesisClaimPeriodID) Validate() error { - if gcp.ID == 0 { - return errors.New("genesis claim period id cannot be 0") - } - if strings.TrimSpace(gcp.CollateralType) == "" { - return fmt.Errorf("collateral type cannot be blank: %v", gcp) - } - return nil -} - -// GenesisClaimPeriodIDs array of GenesisClaimPeriodID -type GenesisClaimPeriodIDs []GenesisClaimPeriodID - -// Validate checks if all the GenesisClaimPeriodIDs are valid and there are no duplicated -// entries. -func (gcps GenesisClaimPeriodIDs) Validate() error { - seenIDS := make(map[string]bool) - var key string - for _, gcp := range gcps { - key = gcp.CollateralType + fmt.Sprint(gcp.ID) - if seenIDS[key] { - return fmt.Errorf("duplicated genesis claim period with id %d and collateral type %s", gcp.ID, gcp.CollateralType) - } - - if err := gcp.Validate(); err != nil { - return err - } - seenIDS[key] = true - } - - return nil -} - // GenesisState is the state that must be provided at genesis. type GenesisState struct { - Params Params `json:"params" yaml:"params"` - PreviousBlockTime time.Time `json:"previous_block_time" yaml:"previous_block_time"` - RewardPeriods RewardPeriods `json:"reward_periods" yaml:"reward_periods"` - ClaimPeriods ClaimPeriods `json:"claim_periods" yaml:"claim_periods"` - Claims Claims `json:"claims" yaml:"claims"` - NextClaimPeriodIDs GenesisClaimPeriodIDs `json:"next_claim_period_ids" yaml:"next_claim_period_ids"` + Params Params `json:"params" yaml:"params"` + PreviousAccumulationTimes GenesisAccumulationTimes `json:"previous_accumulation_times" yaml:"previous_accumulation_times"` + USDXMintingClaims USDXMintingClaims `json:"usdx_minting_claims" yaml:"usdx_minting_claims"` } // NewGenesisState returns a new genesis state -func NewGenesisState(params Params, previousBlockTime time.Time, rp RewardPeriods, cp ClaimPeriods, c Claims, ids GenesisClaimPeriodIDs) GenesisState { +func NewGenesisState(params Params, prevAccumTimes GenesisAccumulationTimes, c USDXMintingClaims) GenesisState { return GenesisState{ - Params: params, - PreviousBlockTime: previousBlockTime, - RewardPeriods: rp, - ClaimPeriods: cp, - Claims: c, - NextClaimPeriodIDs: ids, + Params: params, + PreviousAccumulationTimes: prevAccumTimes, + USDXMintingClaims: c, } } // DefaultGenesisState returns a default genesis state func DefaultGenesisState() GenesisState { return GenesisState{ - Params: DefaultParams(), - PreviousBlockTime: DefaultPreviousBlockTime, - RewardPeriods: RewardPeriods{}, - ClaimPeriods: ClaimPeriods{}, - Claims: Claims{}, - NextClaimPeriodIDs: GenesisClaimPeriodIDs{}, + Params: DefaultParams(), + PreviousAccumulationTimes: GenesisAccumulationTimes{}, + USDXMintingClaims: DefaultClaims, } } @@ -88,19 +39,11 @@ func (gs GenesisState) Validate() error { if err := gs.Params.Validate(); err != nil { return err } - if gs.PreviousBlockTime.IsZero() { - return errors.New("previous block time cannot be 0") - } - if err := gs.RewardPeriods.Validate(); err != nil { + if err := gs.PreviousAccumulationTimes.Validate(); err != nil { return err } - if err := gs.ClaimPeriods.Validate(); err != nil { - return err - } - if err := gs.Claims.Validate(); err != nil { - return err - } - return gs.NextClaimPeriodIDs.Validate() + + return gs.USDXMintingClaims.Validate() } // Equal checks whether two gov GenesisState structs are equivalent @@ -114,3 +57,43 @@ func (gs GenesisState) Equal(gs2 GenesisState) bool { func (gs GenesisState) IsEmpty() bool { return gs.Equal(GenesisState{}) } + +// GenesisAccumulationTime stores the previous reward distribution time and its corresponding collateral type +type GenesisAccumulationTime struct { + CollateralType string `json:"collateral_type" yaml:"collateral_type"` + PreviousAccumulationTime time.Time `json:"previous_accumulation_time" yaml:"previous_accumulation_time"` + RewardFactor sdk.Dec `json:"reward_factor" yaml:"reward_factor"` +} + +// NewGenesisAccumulationTime returns a new GenesisAccumulationTime +func NewGenesisAccumulationTime(ctype string, prevTime time.Time, factor sdk.Dec) GenesisAccumulationTime { + return GenesisAccumulationTime{ + CollateralType: ctype, + PreviousAccumulationTime: prevTime, + RewardFactor: factor, + } +} + +// GenesisAccumulationTimes slice of GenesisAccumulationTime +type GenesisAccumulationTimes []GenesisAccumulationTime + +// Validate performs validation of GenesisAccumulationTimes +func (gats GenesisAccumulationTimes) Validate() error { + for _, gat := range gats { + if err := gat.Validate(); err != nil { + return err + } + } + return nil +} + +// Validate performs validation of GenesisAccumulationTime +func (gat GenesisAccumulationTime) Validate() error { + if gat.RewardFactor == (sdk.Dec{}) { + return fmt.Errorf("reward factor not initialized for %s", gat.CollateralType) + } + if gat.RewardFactor.LT(sdk.ZeroDec()) { + return fmt.Errorf("reward factor should be ≥ 0.0, is %s for %s", gat.RewardFactor, gat.CollateralType) + } + return nil +} diff --git a/x/incentive/types/genesis_test.go b/x/incentive/types/genesis_test.go index 5f690bb9..e9bda436 100644 --- a/x/incentive/types/genesis_test.go +++ b/x/incentive/types/genesis_test.go @@ -1,166 +1,145 @@ package types import ( + "strings" "testing" "time" "github.com/stretchr/testify/require" - tmtypes "github.com/tendermint/tendermint/types" + "github.com/tendermint/tendermint/crypto" sdk "github.com/cosmos/cosmos-sdk/types" ) -func TestGenesisClaimPeriodIDsValidate(t *testing.T) { - testCases := []struct { - msg string - genesisClaimPeriodIDs GenesisClaimPeriodIDs - expPass bool - }{ - { - "valid", - GenesisClaimPeriodIDs{ - {CollateralType: "bnb", ID: 1}, - }, - true, - }, - { - "invalid collateral type", - GenesisClaimPeriodIDs{ - {CollateralType: "", ID: 1}, - }, - false, - }, - { - "invalid ID", - GenesisClaimPeriodIDs{ - {CollateralType: "bnb", ID: 0}, - }, - false, - }, - { - "duplicate", - GenesisClaimPeriodIDs{ - {CollateralType: "bnb", ID: 1}, - {CollateralType: "bnb", ID: 1}, - }, - false, - }, - } - - for _, tc := range testCases { - err := tc.genesisClaimPeriodIDs.Validate() - if tc.expPass { - require.NoError(t, err, tc.msg) - } else { - require.Error(t, err, tc.msg) - } - } -} - func TestGenesisStateValidate(t *testing.T) { - now := time.Now() - mockPrivKey := tmtypes.NewMockPV() - pubkey, err := mockPrivKey.GetPubKey() - require.NoError(t, err) - owner := sdk.AccAddress(pubkey.Address()) - - rewards := Rewards{ - NewReward( - true, "bnb", sdk.NewCoin("ukava", sdk.NewInt(10000000000)), - time.Hour*24*7, Multipliers{NewMultiplier(Small, 1, sdk.MustNewDecFromStr("0.33"))}, time.Hour*24*14, - ), + type args struct { + params Params + genAccTimes GenesisAccumulationTimes + claims USDXMintingClaims + } + + type errArgs struct { + expectPass bool + contains string } - rewardPeriods := RewardPeriods{NewRewardPeriod("bnb", now, now.Add(time.Hour), sdk.NewCoin("bnb", sdk.OneInt()), now, Multipliers{NewMultiplier(Small, 1, sdk.MustNewDecFromStr("0.33"))})} - claimPeriods := ClaimPeriods{NewClaimPeriod("bnb", 10, now, Multipliers{NewMultiplier(Small, 1, sdk.MustNewDecFromStr("0.33"))})} - claims := Claims{NewClaim(owner, sdk.NewCoin("bnb", sdk.OneInt()), "bnb", 10)} - gcps := GenesisClaimPeriodIDs{{CollateralType: "bnb", ID: 1}} testCases := []struct { - msg string - genesisState GenesisState - expPass bool + name string + args args + errArgs errArgs }{ { - msg: "default", - genesisState: DefaultGenesisState(), - expPass: true, + name: "default", + args: args{ + params: DefaultParams(), + genAccTimes: DefaultGenesisAccumulationTimes, + claims: DefaultClaims, + }, + errArgs: errArgs{ + expectPass: true, + contains: "", + }, }, { - msg: "valid genesis", - genesisState: NewGenesisState( - NewParams(true, rewards), - now, rewardPeriods, claimPeriods, claims, gcps, - ), - expPass: true, - }, - { - msg: "invalid Params", - genesisState: GenesisState{ - Params: Params{ - Active: true, - Rewards: Rewards{ - Reward{}, + name: "valid", + args: args{ + params: NewParams(RewardPeriods{NewRewardPeriod(true, "bnb-a", time.Date(2020, 10, 15, 14, 0, 0, 0, time.UTC), time.Date(2024, 10, 15, 14, 0, 0, 0, time.UTC), sdk.NewCoin("ukava", sdk.NewInt(25000)))}, Multipliers{NewMultiplier(Small, 1, sdk.MustNewDecFromStr("0.33"))}, time.Date(2025, 10, 15, 14, 0, 0, 0, time.UTC)), + genAccTimes: GenesisAccumulationTimes{GenesisAccumulationTime{ + CollateralType: "bnb-a", + PreviousAccumulationTime: time.Date(2020, 10, 15, 14, 0, 0, 0, time.UTC), + RewardFactor: sdk.ZeroDec(), + }}, + claims: USDXMintingClaims{ + { + Owner: sdk.AccAddress(crypto.AddressHash([]byte("KavaTestUser1"))), + Reward: sdk.NewCoin("ukava", sdk.NewInt(100000000)), + + RewardIndexes: []RewardIndex{ + { + CollateralType: "bnb-a", + RewardFactor: sdk.ZeroDec(), + }, + }, }, }, }, - expPass: false, - }, - { - msg: "zero PreviousBlockTime", - genesisState: GenesisState{ - PreviousBlockTime: time.Time{}, + errArgs: errArgs{ + expectPass: true, + contains: "", }, - expPass: false, }, { - msg: "invalid RewardsPeriod", - genesisState: GenesisState{ - PreviousBlockTime: now, - RewardPeriods: RewardPeriods{ - {Start: time.Time{}}, + name: "invalid genesis accumulation time", + args: args{ + params: DefaultParams(), + genAccTimes: GenesisAccumulationTimes{ + { + CollateralType: "btcb-a", + RewardFactor: sdk.MustNewDecFromStr("-0.1"), + }, + }, + claims: DefaultClaims, + }, + errArgs: errArgs{ + expectPass: false, + contains: "reward factor should be ≥ 0.0", + }, + }, + { + name: "invalid genesis accumulation time", + args: args{ + params: DefaultParams(), + genAccTimes: GenesisAccumulationTimes{ + { + CollateralType: "btcb-a", + PreviousAccumulationTime: time.Date(2020, 10, 15, 14, 0, 0, 0, time.UTC), + RewardFactor: sdk.Dec{}, + }, + }, + claims: DefaultClaims, + }, + errArgs: errArgs{ + expectPass: false, + contains: "reward factor not initialized", + }, + }, + { + name: "invalid claim", + args: args{ + params: DefaultParams(), + genAccTimes: DefaultGenesisAccumulationTimes, + claims: USDXMintingClaims{ + { + Owner: sdk.AccAddress{}, + Reward: sdk.NewCoin("ukava", sdk.NewInt(100000000)), + + RewardIndexes: []RewardIndex{ + { + CollateralType: "bnb-a", + RewardFactor: sdk.ZeroDec(), + }, + }, + }, }, }, - expPass: false, - }, - { - msg: "invalid ClaimPeriods", - genesisState: GenesisState{ - PreviousBlockTime: now, - ClaimPeriods: ClaimPeriods{ - {ID: 0}, - }, + errArgs: errArgs{ + expectPass: false, + contains: "claim owner cannot be empty", }, - expPass: false, - }, - { - msg: "invalid Claims", - genesisState: GenesisState{ - PreviousBlockTime: now, - Claims: Claims{ - {ClaimPeriodID: 0}, - }, - }, - expPass: false, - }, - { - msg: "invalid NextClaimPeriodIds", - genesisState: GenesisState{ - PreviousBlockTime: now, - NextClaimPeriodIDs: GenesisClaimPeriodIDs{ - {ID: 0}, - }, - }, - expPass: false, }, } for _, tc := range testCases { - err := tc.genesisState.Validate() - if tc.expPass { - require.NoError(t, err, tc.msg) - } else { - require.Error(t, err, tc.msg) - } + t.Run(tc.name, func(t *testing.T) { + gs := NewGenesisState(tc.args.params, tc.args.genAccTimes, tc.args.claims) + err := gs.Validate() + if tc.errArgs.expectPass { + require.NoError(t, err, tc.name) + } else { + require.Error(t, err, tc.name) + require.True(t, strings.Contains(err.Error(), tc.errArgs.contains)) + } + }) } } diff --git a/x/incentive/types/keys.go b/x/incentive/types/keys.go index 31a43558..a930886a 100644 --- a/x/incentive/types/keys.go +++ b/x/incentive/types/keys.go @@ -1,11 +1,5 @@ package types -import ( - "encoding/binary" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - const ( // ModuleName The name that will be used throughout the module ModuleName = "incentive" @@ -25,37 +19,9 @@ const ( // Key Prefixes var ( - RewardPeriodKeyPrefix = []byte{0x01} // prefix for keys that store reward periods - ClaimPeriodKeyPrefix = []byte{0x02} // prefix for keys that store claim periods - ClaimKeyPrefix = []byte{0x03} // prefix for keys that store claims - NextClaimPeriodIDPrefix = []byte{0x04} // prefix for keys that store the next ID for claims periods - PreviousBlockTimeKey = []byte{0x05} // prefix for key that stores the previous blocktime + ClaimKeyPrefix = []byte{0x01} // prefix for keys that store claims + BlockTimeKey = []byte{0x02} // prefix for key that stores the blocktime + RewardFactorKey = []byte{0x03} // prefix for key that stores reward factors + + USDXMintingRewardDenom = "ukava" ) - -// Keys -// 0x00:CollateralType <> RewardPeriod the current active reward period (max 1 reward period per collateral type) -// 0x01:CollateralType:ID <> ClaimPeriod object for that ID, indexed by collateral type and ID -// 0x02:CollateralType:ID:Owner <> Claim object, indexed by collateral type, ID and owner -// 0x03:CollateralType <> NextClaimPeriodIDPrefix the ID of the next claim period, indexed by collateral type - -// BytesToUint64 returns uint64 format from a byte array -func BytesToUint64(bz []byte) uint64 { - return binary.BigEndian.Uint64(bz) -} - -// GetClaimPeriodPrefix returns the key (collateral type + id) for a claim prefix -func GetClaimPeriodPrefix(collateralType string, id uint64) []byte { - return createKey([]byte(collateralType), sdk.Uint64ToBigEndian(id)) -} - -// GetClaimPrefix returns the key (collateral type + id + address) for a claim -func GetClaimPrefix(addr sdk.AccAddress, collateralType string, id uint64) []byte { - return createKey([]byte(collateralType), sdk.Uint64ToBigEndian(id), addr) -} - -func createKey(bytes ...[]byte) (r []byte) { - for _, b := range bytes { - r = append(r, b...) - } - return -} diff --git a/x/incentive/types/msg.go b/x/incentive/types/msg.go index 02e8c923..8d253a2a 100644 --- a/x/incentive/types/msg.go +++ b/x/incentive/types/msg.go @@ -1,7 +1,6 @@ package types import ( - "fmt" "strings" sdk "github.com/cosmos/cosmos-sdk/types" @@ -9,48 +8,43 @@ import ( ) // ensure Msg interface compliance at compile time -var _ sdk.Msg = &MsgClaimReward{} +var _ sdk.Msg = &MsgClaimUSDXMintingReward{} -// MsgClaimReward message type used to claim rewards -type MsgClaimReward struct { +// MsgClaimUSDXMintingReward message type used to claim rewards +type MsgClaimUSDXMintingReward struct { Sender sdk.AccAddress `json:"sender" yaml:"sender"` - CollateralType string `json:"collateral_type" yaml:"collateral_type"` MultiplierName string `json:"multiplier_name" yaml:"multiplier_name"` } -// NewMsgClaimReward returns a new MsgClaimReward. -func NewMsgClaimReward(sender sdk.AccAddress, collateralType, multiplierName string) MsgClaimReward { - return MsgClaimReward{ +// NewMsgClaimUSDXMintingReward returns a new MsgClaimUSDXMintingReward. +func NewMsgClaimUSDXMintingReward(sender sdk.AccAddress, multiplierName string) MsgClaimUSDXMintingReward { + return MsgClaimUSDXMintingReward{ Sender: sender, - CollateralType: collateralType, MultiplierName: multiplierName, } } // Route return the message type used for routing the message. -func (msg MsgClaimReward) Route() string { return RouterKey } +func (msg MsgClaimUSDXMintingReward) Route() string { return RouterKey } // Type returns a human-readable string for the message, intended for utilization within tags. -func (msg MsgClaimReward) Type() string { return "claim_reward" } +func (msg MsgClaimUSDXMintingReward) Type() string { return "claim_reward" } // ValidateBasic does a simple validation check that doesn't require access to state. -func (msg MsgClaimReward) ValidateBasic() error { +func (msg MsgClaimUSDXMintingReward) ValidateBasic() error { if msg.Sender.Empty() { return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "sender address cannot be empty") } - if strings.TrimSpace(msg.CollateralType) == "" { - return fmt.Errorf("collateral type cannot be blank") - } return MultiplierName(strings.ToLower(msg.MultiplierName)).IsValid() } // GetSignBytes gets the canonical byte representation of the Msg. -func (msg MsgClaimReward) GetSignBytes() []byte { +func (msg MsgClaimUSDXMintingReward) GetSignBytes() []byte { bz := ModuleCdc.MustMarshalJSON(msg) return sdk.MustSortJSON(bz) } // GetSigners returns the addresses of signers that must sign. -func (msg MsgClaimReward) GetSigners() []sdk.AccAddress { +func (msg MsgClaimUSDXMintingReward) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.Sender} } diff --git a/x/incentive/types/msg_test.go b/x/incentive/types/msg_test.go index 9f3a44c0..31544f57 100644 --- a/x/incentive/types/msg_test.go +++ b/x/incentive/types/msg_test.go @@ -14,7 +14,6 @@ import ( type msgTest struct { from sdk.AccAddress - collateralType string multiplierName string expectPass bool } @@ -29,25 +28,26 @@ func (suite *MsgTestSuite) SetupTest() { tests := []msgTest{ { from: sdk.AccAddress(crypto.AddressHash([]byte("KavaTest1"))), - collateralType: "bnb", multiplierName: "large", expectPass: true, }, { from: sdk.AccAddress(crypto.AddressHash([]byte("KavaTest1"))), - collateralType: "", + multiplierName: "medium", + expectPass: true, + }, + { + from: sdk.AccAddress(crypto.AddressHash([]byte("KavaTest1"))), multiplierName: "small", - expectPass: false, + expectPass: true, }, { from: sdk.AccAddress{}, - collateralType: "bnb", multiplierName: "medium", expectPass: false, }, { from: sdk.AccAddress(crypto.AddressHash([]byte("KavaTest1"))), - collateralType: "bnb", multiplierName: "huge", expectPass: false, }, @@ -57,7 +57,7 @@ func (suite *MsgTestSuite) SetupTest() { func (suite *MsgTestSuite) TestMsgValidation() { for _, t := range suite.tests { - msg := types.NewMsgClaimReward(t.from, t.collateralType, t.multiplierName) + msg := types.NewMsgClaimUSDXMintingReward(t.from, t.multiplierName) err := msg.ValidateBasic() if t.expectPass { suite.Require().NoError(err) diff --git a/x/incentive/types/params.go b/x/incentive/types/params.go index c1e6ee3d..b79531b1 100644 --- a/x/incentive/types/params.go +++ b/x/incentive/types/params.go @@ -1,6 +1,7 @@ package types import ( + "errors" "fmt" "strings" "time" @@ -23,40 +24,49 @@ const ( // Parameter keys and default values var ( - KeyActive = []byte("Active") - KeyRewards = []byte("Rewards") - DefaultActive = false - DefaultRewards = Rewards{} - DefaultPreviousBlockTime = tmtime.Canonical(time.Unix(0, 0)) - GovDenom = cdptypes.DefaultGovDenom - PrincipalDenom = "usdx" - IncentiveMacc = kavadistTypes.ModuleName + KeyActive = []byte("Active") + KeyRewards = []byte("RewardPeriods") + KeyClaimEnd = []byte("ClaimEnd") + KeyMultipliers = []byte("ClaimMultipliers") + DefaultActive = false + DefaultRewardPeriods = RewardPeriods{} + DefaultMultipliers = Multipliers{} + DefaultClaims = USDXMintingClaims{} + DefaultGenesisAccumulationTimes = GenesisAccumulationTimes{} + DefaultClaimEnd = tmtime.Canonical(time.Unix(0, 0)) + GovDenom = cdptypes.DefaultGovDenom + PrincipalDenom = "usdx" + IncentiveMacc = kavadistTypes.ModuleName ) // Params governance parameters for the incentive module type Params struct { - Active bool `json:"active" yaml:"active"` // top level governance switch to disable all rewards - Rewards Rewards `json:"rewards" yaml:"rewards"` + RewardPeriods RewardPeriods `json:"reward_periods" yaml:"reward_periods"` + ClaimMultipliers Multipliers `json:"claim_multipliers" yaml:"claim_multipliers"` + ClaimEnd time.Time `json:"claim_end" yaml:"claim_end"` } // NewParams returns a new params object -func NewParams(active bool, rewards Rewards) Params { +func NewParams(rewards RewardPeriods, multipliers Multipliers, claimEnd time.Time) Params { return Params{ - Active: active, - Rewards: rewards, + RewardPeriods: rewards, + ClaimMultipliers: multipliers, + ClaimEnd: claimEnd, } } // DefaultParams returns default params for incentive module func DefaultParams() Params { - return NewParams(DefaultActive, DefaultRewards) + return NewParams(DefaultRewardPeriods, DefaultMultipliers, DefaultClaimEnd) } // String implements fmt.Stringer func (p Params) String() string { return fmt.Sprintf(`Params: - Active: %t - Rewards: %s`, p.Active, p.Rewards) + Rewards: %s + Claim Multipliers :%s + Claim End Time: %s + `, p.RewardPeriods, p.ClaimMultipliers, p.ClaimEnd) } // ParamKeyTable Key declaration for parameters @@ -67,18 +77,19 @@ func ParamKeyTable() params.KeyTable { // ParamSetPairs implements the ParamSet interface and returns all the key/value pairs func (p *Params) ParamSetPairs() params.ParamSetPairs { return params.ParamSetPairs{ - params.NewParamSetPair(KeyActive, &p.Active, validateActiveParam), - params.NewParamSetPair(KeyRewards, &p.Rewards, validateRewardsParam), + params.NewParamSetPair(KeyRewards, &p.RewardPeriods, validateRewardsParam), + params.NewParamSetPair(KeyClaimEnd, &p.ClaimEnd, validateClaimEndParam), + params.NewParamSetPair(KeyMultipliers, &p.ClaimMultipliers, validateMultipliersParam), } } // Validate checks that the parameters have valid values. func (p Params) Validate() error { - if err := validateActiveParam(p.Active); err != nil { + if err := validateMultipliersParam(p.ClaimMultipliers); err != nil { return err } - return validateRewardsParam(p.Rewards) + return validateRewardsParam(p.RewardPeriods) } func validateActiveParam(i interface{}) error { @@ -90,7 +101,7 @@ func validateActiveParam(i interface{}) error { } func validateRewardsParam(i interface{}) error { - rewards, ok := i.(Rewards) + rewards, ok := i.(RewardPeriods) if !ok { return fmt.Errorf("invalid parameter type: %T", i) } @@ -98,93 +109,97 @@ func validateRewardsParam(i interface{}) error { return rewards.Validate() } -// Reward stores the specified state for a single reward period. -type Reward struct { - Active bool `json:"active" yaml:"active"` // governance switch to disable a period - CollateralType string `json:"collateral_type" yaml:"collateral_type"` // the collateral type rewards apply to, must be found in the cdp collaterals - AvailableRewards sdk.Coin `json:"available_rewards" yaml:"available_rewards"` // the total amount of coins distributed per period - Duration time.Duration `json:"duration" yaml:"duration"` // the duration of the period - ClaimMultipliers Multipliers `json:"claim_multipliers" yaml:"claim_multipliers"` // the reward multiplier and timelock schedule - applied at the time users claim rewards - ClaimDuration time.Duration `json:"claim_duration" yaml:"claim_duration"` // how long users have after the period ends to claim their rewards +func validateMultipliersParam(i interface{}) error { + multipliers, ok := i.(Multipliers) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + return multipliers.Validate() } -// NewReward returns a new Reward -func NewReward(active bool, collateralType string, reward sdk.Coin, duration time.Duration, multiplier Multipliers, claimDuration time.Duration) Reward { - return Reward{ +func validateClaimEndParam(i interface{}) error { + endTime, ok := i.(time.Time) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + if endTime.IsZero() { + return fmt.Errorf("end time should not be zero") + } + return nil +} + +// RewardPeriod stores the state of an ongoing reward +type RewardPeriod struct { + Active bool `json:"active" yaml:"active"` + CollateralType string `json:"collateral_type" yaml:"collateral_type"` + Start time.Time `json:"start" yaml:"start"` + End time.Time `json:"end" yaml:"end"` + RewardsPerSecond sdk.Coin `json:"rewards_per_second" yaml:"rewards_per_second"` // per second reward payouts +} + +// String implements fmt.Stringer +func (rp RewardPeriod) String() string { + return fmt.Sprintf(`Reward Period: + Collateral Type: %s, + Start: %s, + End: %s, + Rewards Per Second: %s, + Active %t, + `, rp.CollateralType, rp.Start, rp.End, rp.RewardsPerSecond, rp.Active) +} + +// NewRewardPeriod returns a new RewardPeriod +func NewRewardPeriod(active bool, collateralType string, start time.Time, end time.Time, reward sdk.Coin) RewardPeriod { + return RewardPeriod{ Active: active, CollateralType: collateralType, - AvailableRewards: reward, - Duration: duration, - ClaimMultipliers: multiplier, - ClaimDuration: claimDuration, + Start: start, + End: end, + RewardsPerSecond: reward, } } -// String implements fmt.Stringer -func (r Reward) String() string { - return fmt.Sprintf(`Reward: - Active: %t, - CollateralType: %s, - Available Rewards: %s, - Duration: %s, - %s, - Claim Duration: %s`, - r.Active, r.CollateralType, r.AvailableRewards, r.Duration, r.ClaimMultipliers, r.ClaimDuration) -} - -// Validate performs a basic check of a reward fields. -func (r Reward) Validate() error { - if !r.AvailableRewards.IsValid() { - return fmt.Errorf("invalid reward coins %s for %s", r.AvailableRewards, r.CollateralType) +// Validate performs a basic check of a RewardPeriod fields. +func (rp RewardPeriod) Validate() error { + if rp.Start.IsZero() { + return errors.New("reward period start time cannot be 0") } - if !r.AvailableRewards.IsPositive() { - return fmt.Errorf("reward amount must be positive, is %s for %s", r.AvailableRewards, r.CollateralType) + if rp.End.IsZero() { + return errors.New("reward period end time cannot be 0") } - if r.Duration <= 0 { - return fmt.Errorf("reward duration must be positive, is %s for %s", r.Duration, r.CollateralType) + if rp.Start.After(rp.End) { + return fmt.Errorf("end period time %s cannot be before start time %s", rp.End, rp.Start) } - if err := r.ClaimMultipliers.Validate(); err != nil { - return err + if !rp.RewardsPerSecond.IsValid() { + return fmt.Errorf("invalid reward amount: %s", rp.RewardsPerSecond) } - if r.ClaimDuration <= 0 { - return fmt.Errorf("claim duration must be positive, is %s for %s", r.ClaimDuration, r.CollateralType) - } - if strings.TrimSpace(r.CollateralType) == "" { - return fmt.Errorf("collateral type cannot be blank: %s", r) + if strings.TrimSpace(rp.CollateralType) == "" { + return fmt.Errorf("reward period collateral type cannot be blank: %s", rp) } return nil } -// Rewards array of Reward -type Rewards []Reward +// RewardPeriods array of RewardPeriod +type RewardPeriods []RewardPeriod -// Validate checks if all the rewards are valid and there are no duplicated +// Validate checks if all the RewardPeriods are valid and there are no duplicated // entries. -func (rs Rewards) Validate() error { - rewardCollateralTypes := make(map[string]bool) - for _, r := range rs { - if rewardCollateralTypes[r.CollateralType] { - return fmt.Errorf("cannot have duplicate reward collateral types: %s", r.CollateralType) +func (rps RewardPeriods) Validate() error { + seenPeriods := make(map[string]bool) + for _, rp := range rps { + if seenPeriods[rp.CollateralType] { + return fmt.Errorf("duplicated reward period with collateral type %s", rp.CollateralType) } - if err := r.Validate(); err != nil { + if err := rp.Validate(); err != nil { return err } - - rewardCollateralTypes[r.CollateralType] = true + seenPeriods[rp.CollateralType] = true } + return nil } -// String implements fmt.Stringer -func (rs Rewards) String() string { - out := "Rewards\n" - for _, r := range rs { - out += fmt.Sprintf("%s\n", r) - } - return out -} - // Multiplier amount the claim rewards get increased by, along with how long the claim rewards are locked type Multiplier struct { Name MultiplierName `json:"name" yaml:"name"` @@ -209,6 +224,9 @@ func (m Multiplier) Validate() error { if m.MonthsLockup < 0 { return fmt.Errorf("expected non-negative lockup, got %d", m.MonthsLockup) } + if m.Factor == (sdk.Dec{}) { + return fmt.Errorf("claim multiplier factor not initialized for %s", m.Name) + } if m.Factor.IsNegative() { return fmt.Errorf("expected non-negative factor, got %s", m.Factor.String()) } diff --git a/x/incentive/types/params_test.go b/x/incentive/types/params_test.go index f1ba6251..ab33b02d 100644 --- a/x/incentive/types/params_test.go +++ b/x/incentive/types/params_test.go @@ -5,212 +5,104 @@ import ( "testing" "time" - "github.com/stretchr/testify/suite" - sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/suite" + "github.com/kava-labs/kava/x/incentive/types" ) -type paramTest struct { - name string - params types.Params - errResult errResult -} - -type errResult struct { - expectPass bool - contains string -} - type ParamTestSuite struct { suite.Suite - - tests []paramTest } -func (suite *ParamTestSuite) SetupTest() { - suite.tests = []paramTest{ +func (suite *ParamTestSuite) SetupTest() {} + +func (suite *ParamTestSuite) TestParamValidation() { + type args struct { + rewardPeriods types.RewardPeriods + multipliers types.Multipliers + end time.Time + } + + type errArgs struct { + expectPass bool + contains string + } + type test struct { + name string + args args + errArgs errArgs + } + + testCases := []test{ { - name: "valid - active", - params: types.Params{ - Active: true, - Rewards: types.Rewards{ - types.Reward{ - Active: true, - CollateralType: "bnb-a", - AvailableRewards: sdk.NewCoin("ukava", sdk.NewInt(10000000000)), - Duration: time.Hour * 24 * 7, - ClaimMultipliers: types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))}, - ClaimDuration: time.Hour * 24 * 14, - }, - }, + "default", + args{ + rewardPeriods: types.DefaultRewardPeriods, + multipliers: types.DefaultMultipliers, + end: types.DefaultClaimEnd, }, - errResult: errResult{ + errArgs{ expectPass: true, contains: "", }, }, { - name: "valid - inactive", - params: types.Params{ - Active: false, - Rewards: types.Rewards{ - types.Reward{ - Active: true, - CollateralType: "bnb-a", - AvailableRewards: sdk.NewCoin("ukava", sdk.NewInt(10000000000)), - Duration: time.Hour * 24 * 7, - ClaimMultipliers: types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))}, - ClaimDuration: time.Hour * 24 * 14, - }, + "valid", + args{ + rewardPeriods: types.RewardPeriods{types.NewRewardPeriod( + true, "bnb-a", time.Date(2020, 10, 15, 14, 0, 0, 0, time.UTC), time.Date(2024, 10, 15, 14, 0, 0, 0, time.UTC), + sdk.NewCoin(types.USDXMintingRewardDenom, sdk.NewInt(122354)))}, + multipliers: types.Multipliers{ + types.NewMultiplier( + types.Small, 1, sdk.MustNewDecFromStr("0.25"), + ), + types.NewMultiplier( + types.Large, 1, sdk.MustNewDecFromStr("1.0"), + ), }, + end: time.Date(2025, 10, 15, 14, 0, 0, 0, time.UTC), }, - errResult: errResult{ + errArgs{ expectPass: true, contains: "", }, }, { - name: "duplicate reward", - params: types.Params{ - Active: true, - Rewards: types.Rewards{ - types.Reward{ - Active: true, - CollateralType: "bnb-a", - AvailableRewards: sdk.NewCoin("ukava", sdk.NewInt(10000000000)), - Duration: time.Hour * 24 * 7, - ClaimMultipliers: types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))}, - ClaimDuration: time.Hour * 24 * 14, - }, - types.Reward{ - Active: true, - CollateralType: "bnb-a", - AvailableRewards: sdk.NewCoin("ukava", sdk.NewInt(10000000000)), - Duration: time.Hour * 24 * 7, - ClaimMultipliers: types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))}, - ClaimDuration: time.Hour * 24 * 14, - }, + "invalid: empty reward factor", + args{ + rewardPeriods: types.RewardPeriods{types.NewRewardPeriod( + true, "bnb-a", time.Date(2020, 10, 15, 14, 0, 0, 0, time.UTC), time.Date(2024, 10, 15, 14, 0, 0, 0, time.UTC), + sdk.NewCoin(types.USDXMintingRewardDenom, sdk.NewInt(122354)))}, + multipliers: types.Multipliers{ + types.NewMultiplier( + types.Small, 1, sdk.MustNewDecFromStr("0.25"), + ), + types.NewMultiplier( + types.Large, 1, sdk.Dec{}, + ), }, + end: time.Date(2025, 10, 15, 14, 0, 0, 0, time.UTC), }, - errResult: errResult{ + errArgs{ expectPass: false, - contains: "cannot have duplicate reward collateral type", - }, - }, - { - name: "negative reward duration", - params: types.Params{ - Active: true, - Rewards: types.Rewards{ - types.Reward{ - Active: true, - CollateralType: "bnb-a", - AvailableRewards: sdk.NewCoin("ukava", sdk.NewInt(10000000000)), - Duration: time.Hour * -24 * 7, - ClaimMultipliers: types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))}, - ClaimDuration: time.Hour * 24 * 14, - }, - }, - }, - errResult: errResult{ - expectPass: false, - contains: "reward duration must be positive", - }, - }, - { - name: "negative time lock", - params: types.Params{ - Active: true, - Rewards: types.Rewards{ - types.Reward{ - Active: true, - CollateralType: "bnb-a", - AvailableRewards: sdk.NewCoin("ukava", sdk.NewInt(10000000000)), - Duration: time.Hour * 24 * 7, - ClaimMultipliers: types.Multipliers{types.NewMultiplier(types.Small, -1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))}, - ClaimDuration: time.Hour * 24 * 14, - }, - }, - }, - errResult: errResult{ - expectPass: false, - contains: "expected non-negative lockup", - }, - }, - { - name: "zero claim duration", - params: types.Params{ - Active: true, - Rewards: types.Rewards{ - types.Reward{ - Active: true, - CollateralType: "bnb-a", - AvailableRewards: sdk.NewCoin("ukava", sdk.NewInt(10000000000)), - Duration: time.Hour * 24 * 7, - ClaimMultipliers: types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))}, - ClaimDuration: time.Hour * 0, - }, - }, - }, - errResult: errResult{ - expectPass: false, - contains: "claim duration must be positive", - }, - }, - { - name: "zero reward", - params: types.Params{ - Active: true, - Rewards: types.Rewards{ - types.Reward{ - Active: true, - CollateralType: "bnb-a", - AvailableRewards: sdk.NewCoin("ukava", sdk.NewInt(0)), - Duration: time.Hour * 24 * 7, - ClaimMultipliers: types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))}, - ClaimDuration: time.Hour * 24 * 14, - }, - }, - }, - errResult: errResult{ - expectPass: false, - contains: "reward amount must be positive", - }, - }, - { - name: "empty reward collateral type", - params: types.Params{ - Active: true, - Rewards: types.Rewards{ - types.Reward{ - Active: true, - CollateralType: "", - AvailableRewards: sdk.NewCoin("ukava", sdk.NewInt(1)), - Duration: time.Hour * 24 * 7, - ClaimMultipliers: types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))}, - ClaimDuration: time.Hour * 24 * 14, - }, - }, - }, - errResult: errResult{ - expectPass: false, - contains: "collateral type cannot be blank", + contains: "claim multiplier factor not initialized", }, }, } -} -func (suite *ParamTestSuite) TestParamValidation() { - for _, t := range suite.tests { - suite.Run(t.name, func() { - err := t.params.Validate() - if t.errResult.expectPass { + for _, tc := range testCases { + suite.Run(tc.name, func() { + params := types.NewParams( + tc.args.rewardPeriods, tc.args.multipliers, tc.args.end, + ) + err := params.Validate() + if tc.errArgs.expectPass { suite.Require().NoError(err) } else { suite.Require().Error(err) - suite.Require().True(strings.Contains(err.Error(), t.errResult.contains)) + suite.Require().True(strings.Contains(err.Error(), tc.errArgs.contains)) } }) } diff --git a/x/incentive/types/querier.go b/x/incentive/types/querier.go index e02b4347..d13c1027 100644 --- a/x/incentive/types/querier.go +++ b/x/incentive/types/querier.go @@ -17,15 +17,17 @@ const ( // QueryClaimsParams params for query /incentive/claims type QueryClaimsParams struct { - Owner sdk.AccAddress - CollateralType string + Page int `json:"page" yaml:"page"` + Limit int `json:"limit" yaml:"limit"` + Owner sdk.AccAddress } // NewQueryClaimsParams returns QueryClaimsParams -func NewQueryClaimsParams(owner sdk.AccAddress, collateralType string) QueryClaimsParams { +func NewQueryClaimsParams(page, limit int, owner sdk.AccAddress) QueryClaimsParams { return QueryClaimsParams{ - Owner: owner, - CollateralType: collateralType, + Page: page, + Limit: limit, + Owner: owner, } } @@ -33,6 +35,5 @@ func NewQueryClaimsParams(owner sdk.AccAddress, collateralType string) QueryClai type PostClaimReq struct { BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` Sender sdk.AccAddress `json:"sender" yaml:"sender"` - CollateralType string `json:"collateral_type" yaml:"collateral_type"` MultiplierName string `json:"multiplier_name" yaml:"multiplier_name"` } diff --git a/x/incentive/types/rewards.go b/x/incentive/types/rewards.go deleted file mode 100644 index a1b100d0..00000000 --- a/x/incentive/types/rewards.go +++ /dev/null @@ -1,281 +0,0 @@ -package types - -import ( - "errors" - "fmt" - "strings" - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// RewardPeriod stores the state of an ongoing reward -type RewardPeriod struct { - CollateralType string `json:"collateral_type" yaml:"collateral_type"` - Start time.Time `json:"start" yaml:"start"` - End time.Time `json:"end" yaml:"end"` - Reward sdk.Coin `json:"reward" yaml:"reward"` // per second reward payouts - ClaimEnd time.Time `json:"claim_end" yaml:"claim_end"` - ClaimMultipliers Multipliers `json:"claim_multipliers" yaml:"claim_multipliers"` // the reward multiplier and timelock schedule - applied at the time users claim rewards -} - -// String implements fmt.Stringer -func (rp RewardPeriod) String() string { - return fmt.Sprintf(`Reward Period: - Collateral Type: %s, - Start: %s, - End: %s, - Reward: %s, - Claim End: %s, - %s - `, rp.CollateralType, rp.Start, rp.End, rp.Reward, rp.ClaimEnd, rp.ClaimMultipliers) -} - -// NewRewardPeriod returns a new RewardPeriod -func NewRewardPeriod(collateralType string, start time.Time, end time.Time, reward sdk.Coin, claimEnd time.Time, claimMultipliers Multipliers) RewardPeriod { - return RewardPeriod{ - CollateralType: collateralType, - Start: start, - End: end, - Reward: reward, - ClaimEnd: claimEnd, - ClaimMultipliers: claimMultipliers, - } -} - -// Validate performs a basic check of a RewardPeriod fields. -func (rp RewardPeriod) Validate() error { - if rp.Start.IsZero() { - return errors.New("reward period start time cannot be 0") - } - if rp.End.IsZero() { - return errors.New("reward period end time cannot be 0") - } - if rp.Start.After(rp.End) { - return fmt.Errorf("end period time %s cannot be before start time %s", rp.End, rp.Start) - } - if !rp.Reward.IsValid() { - return fmt.Errorf("invalid reward amount: %s", rp.Reward) - } - if rp.ClaimEnd.IsZero() { - return errors.New("reward period claim end time cannot be 0") - } - if err := rp.ClaimMultipliers.Validate(); err != nil { - return err - } - if strings.TrimSpace(rp.CollateralType) == "" { - return fmt.Errorf("reward period collateral type cannot be blank: %s", rp) - } - return nil -} - -// RewardPeriods array of RewardPeriod -type RewardPeriods []RewardPeriod - -// Validate checks if all the RewardPeriods are valid and there are no duplicated -// entries. -func (rps RewardPeriods) Validate() error { - seenPeriods := make(map[string]bool) - for _, rp := range rps { - if seenPeriods[rp.CollateralType] { - return fmt.Errorf("duplicated reward period with collateral type %s", rp.CollateralType) - } - - if err := rp.Validate(); err != nil { - return err - } - seenPeriods[rp.CollateralType] = true - } - - return nil -} - -// ClaimPeriod stores the state of an ongoing claim period -type ClaimPeriod struct { - CollateralType string `json:"collateral_type" yaml:"collateral_type"` - ID uint64 `json:"id" yaml:"id"` - End time.Time `json:"end" yaml:"end"` - ClaimMultipliers Multipliers `json:"claim_multipliers" yaml:"claim_multipliers"` -} - -// NewClaimPeriod returns a new ClaimPeriod -func NewClaimPeriod(collateralType string, id uint64, end time.Time, multipliers Multipliers) ClaimPeriod { - return ClaimPeriod{ - CollateralType: collateralType, - ID: id, - End: end, - ClaimMultipliers: multipliers, - } -} - -// Validate performs a basic check of a ClaimPeriod fields. -func (cp ClaimPeriod) Validate() error { - if cp.ID == 0 { - return errors.New("claim period id cannot be 0") - } - if cp.End.IsZero() { - return errors.New("claim period end time cannot be 0") - } - if err := cp.ClaimMultipliers.Validate(); err != nil { - return err - } - if strings.TrimSpace(cp.CollateralType) == "" { - return fmt.Errorf("claim period collateral type cannot be blank: %s", cp) - } - return nil -} - -// String implements fmt.Stringer -func (cp ClaimPeriod) String() string { - return fmt.Sprintf(`Claim Period: - Collateral Type: %s, - ID: %d, - End: %s, - %s - `, cp.CollateralType, cp.ID, cp.End, cp.ClaimMultipliers) -} - -// GetMultiplier returns the named multiplier from the input claim period -func (cp ClaimPeriod) GetMultiplier(name MultiplierName) (Multiplier, bool) { - for _, multiplier := range cp.ClaimMultipliers { - if multiplier.Name == name { - return multiplier, true - } - } - return Multiplier{}, false -} - -// ClaimPeriods array of ClaimPeriod -type ClaimPeriods []ClaimPeriod - -// Validate checks if all the ClaimPeriods are valid and there are no duplicated -// entries. -func (cps ClaimPeriods) Validate() error { - seenPeriods := make(map[string]bool) - var key string - for _, cp := range cps { - key = cp.CollateralType + fmt.Sprint(cp.ID) - if seenPeriods[key] { - return fmt.Errorf("duplicated claim period with id %d and collateral type %s", cp.ID, cp.CollateralType) - } - - if err := cp.Validate(); err != nil { - return err - } - seenPeriods[key] = true - } - - return nil -} - -// Claim stores the rewards that can be claimed by owner -type Claim struct { - Owner sdk.AccAddress `json:"owner" yaml:"owner"` - Reward sdk.Coin `json:"reward" yaml:"reward"` - CollateralType string `json:"collateral_type" yaml:"collateral_type"` - ClaimPeriodID uint64 `json:"claim_period_id" yaml:"claim_period_id"` -} - -// NewClaim returns a new Claim -func NewClaim(owner sdk.AccAddress, reward sdk.Coin, collateralType string, claimPeriodID uint64) Claim { - return Claim{ - Owner: owner, - Reward: reward, - CollateralType: collateralType, - ClaimPeriodID: claimPeriodID, - } -} - -// Validate performs a basic check of a Claim fields. -func (c Claim) Validate() error { - if c.Owner.Empty() { - return errors.New("claim owner cannot be empty") - } - if !c.Reward.IsValid() { - return fmt.Errorf("invalid reward amount: %s", c.Reward) - } - if c.ClaimPeriodID == 0 { - return errors.New("claim period id cannot be 0") - } - if strings.TrimSpace(c.CollateralType) == "" { - return fmt.Errorf("claim collateral type cannot be blank: %s", c) - } - return nil -} - -// String implements fmt.Stringer -func (c Claim) String() string { - return fmt.Sprintf(`Claim: - Owner: %s, - Collateral Type: %s, - Reward: %s, - Claim Period ID: %d, - `, c.Owner, c.CollateralType, c.Reward, c.ClaimPeriodID) -} - -// Claims array of Claim -type Claims []Claim - -// AugmentedClaim claim type with information about whether the claim is currently claimable -type AugmentedClaim struct { - Claim Claim `json:"claim" yaml:"claim"` - - Claimable bool `json:"claimable" yaml:"claimable"` -} - -func (ac AugmentedClaim) String() string { - return fmt.Sprintf(`Claim: - Owner: %s, - Collateral Type: %s, - Reward: %s, - Claim Period ID: %d, - Claimable: %t, - `, ac.Claim.Owner, ac.Claim.CollateralType, ac.Claim.Reward, ac.Claim.ClaimPeriodID, ac.Claimable, - ) -} - -// NewAugmentedClaim returns a new augmented claim struct -func NewAugmentedClaim(claim Claim, claimable bool) AugmentedClaim { - return AugmentedClaim{ - Claim: claim, - Claimable: claimable, - } -} - -// AugmentedClaims array of AugmentedClaim -type AugmentedClaims []AugmentedClaim - -// Validate checks if all the claims are valid and there are no duplicated -// entries. -func (cs Claims) Validate() error { - seemClaims := make(map[string]bool) - var key string - for _, c := range cs { - key = c.CollateralType + fmt.Sprint(c.ClaimPeriodID) + c.Owner.String() - if c.Owner != nil && seemClaims[key] { - return fmt.Errorf("duplicated claim from owner %s and collateral type %s", c.Owner, c.CollateralType) - } - - if err := c.Validate(); err != nil { - return err - } - seemClaims[key] = true - } - - return nil -} - -// NewRewardPeriodFromReward returns a new reward period from the input reward and block time -func NewRewardPeriodFromReward(reward Reward, blockTime time.Time) RewardPeriod { - // note: reward periods store the amount of rewards paid PER SECOND - rewardsPerSecond := sdk.NewDecFromInt(reward.AvailableRewards.Amount).Quo(sdk.NewDecFromInt(sdk.NewInt(int64(reward.Duration.Seconds())))).TruncateInt() - rewardCoinPerSecond := sdk.NewCoin(reward.AvailableRewards.Denom, rewardsPerSecond) - return RewardPeriod{ - CollateralType: reward.CollateralType, - Start: blockTime, - End: blockTime.Add(reward.Duration), - Reward: rewardCoinPerSecond, - ClaimEnd: blockTime.Add(reward.Duration).Add(reward.ClaimDuration), - ClaimMultipliers: reward.ClaimMultipliers, - } -} diff --git a/x/incentive/types/rewards_test.go b/x/incentive/types/rewards_test.go deleted file mode 100644 index 2d9531c4..00000000 --- a/x/incentive/types/rewards_test.go +++ /dev/null @@ -1,282 +0,0 @@ -package types - -import ( - "testing" - "time" - - "github.com/stretchr/testify/require" - tmtypes "github.com/tendermint/tendermint/types" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -func TestRewardPeriodsValidate(t *testing.T) { - now := time.Now() - - testCases := []struct { - msg string - rewardPeriods RewardPeriods - expPass bool - }{ - { - "valid", - RewardPeriods{ - NewRewardPeriod("bnb", now, now.Add(time.Hour), sdk.NewCoin("bnb", sdk.OneInt()), now, Multipliers{NewMultiplier(Small, 1, sdk.MustNewDecFromStr("0.33"))}), - }, - true, - }, - { - "zero start time", - RewardPeriods{ - {Start: time.Time{}}, - }, - false, - }, - { - "zero end time", - RewardPeriods{ - {Start: now, End: time.Time{}}, - }, - false, - }, - { - "zero end time", - RewardPeriods{ - {Start: now, End: time.Time{}}, - }, - false, - }, - { - "start time > end time", - RewardPeriods{ - { - Start: now.Add(time.Hour), - End: now, - }, - }, - false, - }, - { - "invalid reward", - RewardPeriods{ - { - Start: now, - End: now.Add(time.Hour), - Reward: sdk.Coin{Denom: "", Amount: sdk.ZeroInt()}, - }, - }, - false, - }, - { - "zero claim end time", - RewardPeriods{ - { - Start: now, - End: now.Add(time.Hour), - Reward: sdk.NewCoin("bnb", sdk.OneInt()), - ClaimEnd: time.Time{}, - }, - }, - false, - }, - { - "negative time lock", - RewardPeriods{ - { - Start: now, - End: now.Add(time.Hour), - Reward: sdk.NewCoin("bnb", sdk.OneInt()), - ClaimEnd: now, - ClaimMultipliers: Multipliers{NewMultiplier(Small, -1, sdk.MustNewDecFromStr("0.33"))}, - }, - }, - false, - }, - { - "invalid collateral type", - RewardPeriods{ - { - Start: now, - End: now.Add(time.Hour), - Reward: sdk.NewCoin("bnb", sdk.OneInt()), - ClaimEnd: now, - ClaimMultipliers: Multipliers{NewMultiplier(Small, 1, sdk.MustNewDecFromStr("0.33"))}, - CollateralType: "", - }, - }, - false, - }, - { - "duplicate reward period", - RewardPeriods{ - NewRewardPeriod("bnb", now, now.Add(time.Hour), sdk.NewCoin("bnb", sdk.OneInt()), now, Multipliers{NewMultiplier(Small, 1, sdk.MustNewDecFromStr("0.33"))}), - NewRewardPeriod("bnb", now, now.Add(time.Hour), sdk.NewCoin("bnb", sdk.OneInt()), now, Multipliers{NewMultiplier(Small, 1, sdk.MustNewDecFromStr("0.33"))}), - }, - false, - }, - } - - for _, tc := range testCases { - err := tc.rewardPeriods.Validate() - if tc.expPass { - require.NoError(t, err, tc.msg) - } else { - require.Error(t, err, tc.msg) - } - } -} - -func TestClaimPeriodsValidate(t *testing.T) { - now := time.Now() - - testCases := []struct { - msg string - claimPeriods ClaimPeriods - expPass bool - }{ - { - "valid", - ClaimPeriods{ - NewClaimPeriod("bnb", 10, now, Multipliers{NewMultiplier(Small, 1, sdk.MustNewDecFromStr("0.33"))}), - }, - true, - }, - { - "invalid ID", - ClaimPeriods{ - {ID: 0}, - }, - false, - }, - { - "zero end time", - ClaimPeriods{ - {ID: 10, End: time.Time{}}, - }, - false, - }, - { - "negative time lock", - ClaimPeriods{ - {ID: 10, End: now, ClaimMultipliers: Multipliers{NewMultiplier(Small, -1, sdk.MustNewDecFromStr("0.33"))}}, - }, - false, - }, - { - "negative multiplier", - ClaimPeriods{ - NewClaimPeriod("bnb", 10, now, Multipliers{NewMultiplier(Small, 1, sdk.MustNewDecFromStr("-0.33"))}), - }, - false, - }, - { - "start time > end time", - ClaimPeriods{ - {ID: 10, End: now, ClaimMultipliers: Multipliers{NewMultiplier(Small, -1, sdk.MustNewDecFromStr("0.33"))}}, - }, - false, - }, - { - "invalid collateral type", - ClaimPeriods{ - {ID: 10, End: now, ClaimMultipliers: Multipliers{NewMultiplier(Small, -1, sdk.MustNewDecFromStr("0.33"))}, CollateralType: ""}, - }, - false, - }, - { - "duplicate reward period", - ClaimPeriods{ - NewClaimPeriod("bnb", 10, now, Multipliers{NewMultiplier(Small, -1, sdk.MustNewDecFromStr("0.33"))}), - NewClaimPeriod("bnb", 10, now, Multipliers{NewMultiplier(Small, -1, sdk.MustNewDecFromStr("0.33"))}), - }, - false, - }, - } - - for _, tc := range testCases { - err := tc.claimPeriods.Validate() - if tc.expPass { - require.NoError(t, err, tc.msg) - } else { - require.Error(t, err, tc.msg) - } - } -} - -func TestClaimsValidate(t *testing.T) { - mockPrivKey := tmtypes.NewMockPV() - pubkey, err := mockPrivKey.GetPubKey() - require.NoError(t, err) - owner := sdk.AccAddress(pubkey.Address()) - - testCases := []struct { - msg string - claims Claims - expPass bool - }{ - { - "valid", - Claims{ - NewClaim(owner, sdk.NewCoin("bnb", sdk.OneInt()), "bnb", 10), - }, - true, - }, - { - "invalid owner", - Claims{ - {Owner: nil}, - }, - false, - }, - { - "invalid reward", - Claims{ - { - Owner: owner, - Reward: sdk.Coin{Denom: "", Amount: sdk.ZeroInt()}, - }, - }, - false, - }, - { - "zero claim period id", - Claims{ - { - Owner: owner, - Reward: sdk.NewCoin("bnb", sdk.OneInt()), - ClaimPeriodID: 0, - }, - }, - false, - }, - { - "invalid collateral type", - Claims{ - { - Owner: owner, - Reward: sdk.NewCoin("bnb", sdk.OneInt()), - ClaimPeriodID: 10, - CollateralType: "", - }, - }, - false, - }, - { - "duplicate reward period", - Claims{ - NewClaim(owner, sdk.NewCoin("bnb", sdk.OneInt()), "bnb", 10), - NewClaim(owner, sdk.NewCoin("bnb", sdk.OneInt()), "bnb", 10), - }, - false, - }, - } - - for _, tc := range testCases { - err := tc.claims.Validate() - if tc.expPass { - require.NoError(t, err, tc.msg) - } else { - require.Error(t, err, tc.msg) - } - } -}