Files
wasmd/x/wasm/keeper/staking_test.go
Alexander Peters 7e936c7fff Cosmos-SDK v0.47 integration brach (#1149)
* Start cosmos-sdk v0.47 integration (#1136)

* Upgrade to sdk v0.47 branch

* More integration work

* SDK version upgrade; fixes

* More fixes

* Fixes

* Deactivate failing tests

* SDK + ibc-go version upgrades

* limix gas fix

(cherry picked from commit f7f841768e5051d96d243b42ce4f231a33020326)

* with valset in bench

(cherry picked from commit 35b2a8fd2c23d6160fca540771fd348913f7f143)

* Revert staking query handler; fix tests

* Minor cleanup

* Rebased

* Address linter issues

* Set legacy router proper

* Deactivate failing test. Race condition needs to handled in SDK

* Address some code smells

* Bump sdk version

* Use gov v1 internally for votes

* Activate test after sdk fix

* Add group test

* Add config template for wasm fields

* Add Rust backtrace flag for more debug output on simulations

* Set unique node folder for tests

* Revert "Add Rust backtrace flag for more debug output on simulations"

This reverts commit 218c3c6ce137dc02f7bc38391408d3460fb27e6f.

* Simulations

* Run also im/export + deterministic sims

* Add package prefix to interfaces

* Add signer annotation (https://github.com/cosmos/cosmos-sdk/issues/10933), minor cleanup

* Bump sdk version

* Review comments

Co-authored-by: vuong <nguyenvuong1122000@gmail.com>

* Bump bufbuild/buf-setup-action from 1.11.0 to 1.12.0

Bumps [bufbuild/buf-setup-action](https://github.com/bufbuild/buf-setup-action) from 1.11.0 to 1.12.0.
- [Release notes](https://github.com/bufbuild/buf-setup-action/releases)
- [Commits](https://github.com/bufbuild/buf-setup-action/compare/v1.11.0...v1.12.0)

---
updated-dependencies:
- dependency-name: bufbuild/buf-setup-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
(cherry picked from commit f4905955b5)

* Remove intertx for vanilla ICA

* fix msg format in EVENTS.md

(cherry picked from commit 38d466adfd)

* Better to sdk coin convertion (#1164)

* Better to sdk coin convertion

* Review feedback

(cherry picked from commit a925a9ed61)

* Disallow only address permission (#1163)

* Remove AccessTypeOnlyAddress for store msg

* Remove AccessTypeOnlyAddress for update config msg

* Review feedback

Co-authored-by: Simon Warta <2603011+webmaster128@users.noreply.github.com>

Co-authored-by: Simon Warta <2603011+webmaster128@users.noreply.github.com>
(cherry picked from commit 8991633de2)

* Integrate wasmvm v1.2.0 (backport #1161) (#1175)

* Integrate wasmvm v1.2.0 (#1161)

* Bump wasmvm version

* Bump wasm test contracts

* Encode weighted votes

* Encode instantiate2

* Handle code info query; better wasmvm errors

* Fix readme

* Make linter happy

* add non cgo build

* Review comments

* Bump wasmvm to release version

Co-authored-by: jhernandezb <contact@jhernandez.me>
(cherry picked from commit 957b38e0a5)

# Conflicts:
#	x/wasm/keeper/handler_plugin_encoders.go
#	x/wasm/keeper/handler_plugin_encoders_test.go
#	x/wasm/keeper/keeper.go
#	x/wasm/keeper/keeper_test.go

* Adress merge conflicts

Co-authored-by: Alexander Peters <alpe@users.noreply.github.com>

* Bump bufbuild/buf-setup-action from 1.12.0 to 1.13.0

Bumps [bufbuild/buf-setup-action](https://github.com/bufbuild/buf-setup-action) from 1.12.0 to 1.13.0.
- [Release notes](https://github.com/bufbuild/buf-setup-action/releases)
- [Commits](https://github.com/bufbuild/buf-setup-action/compare/v1.12.0...v1.13.0)

---
updated-dependencies:
- dependency-name: bufbuild/buf-setup-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
(cherry picked from commit ffa0e5e5e1)

* Emit events for setContractAdmin + setAccessConfig (#1179)

(cherry picked from commit c9e7830ac1)

* Dependency upgrades (#1172)

* Bump sdk version to lastest

* Bump ibc-go  version to lastest

* Remove channel hack

* Update to ibc-go v7 + protoVer=0.11.5

* Bump bufbuild/buf-setup-action from 1.13.0 to 1.13.1

Bumps [bufbuild/buf-setup-action](https://github.com/bufbuild/buf-setup-action) from 1.13.0 to 1.13.1.
- [Release notes](https://github.com/bufbuild/buf-setup-action/releases)
- [Commits](https://github.com/bufbuild/buf-setup-action/compare/v1.13.0...v1.13.1)

---
updated-dependencies:
- dependency-name: bufbuild/buf-setup-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
(cherry picked from commit de27e7f82f)

* Fix typos (backport #1185) (#1194)

* Fix typos

(cherry picked from commit c88b8194cb)

# Conflicts:
#	proto/cosmwasm/wasm/v1/tx.proto

* Fix merge conflict

---------

Co-authored-by: Alex Peters <alpe@users.noreply.github.com>

* Bump bufbuild/buf-setup-action from 1.13.1 to 1.14.0 (#1200)

Bumps [bufbuild/buf-setup-action](https://github.com/bufbuild/buf-setup-action) from 1.13.1 to 1.14.0.
- [Release notes](https://github.com/bufbuild/buf-setup-action/releases)
- [Commits](https://github.com/bufbuild/buf-setup-action/compare/v1.13.1...v1.14.0)

---
updated-dependencies:
- dependency-name: bufbuild/buf-setup-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
(cherry picked from commit f3fc31c386)

* list-contract-by-code bugfix

(cherry picked from commit 2ccffed778)

* fix: stargate querier does not reset the state

(cherry picked from commit fd0323541d)

* test: add unit test

(cherry picked from commit 6d8018ac59)

* Add Windows client support (#1197)

* Add Windows client support

* Separate server and windows client

---------

Co-authored-by: Alex Peters <alpe@users.noreply.github.com>
(cherry picked from commit 8a20779518)

* Bump bufbuild/buf-setup-action from 1.14.0 to 1.15.0

Bumps [bufbuild/buf-setup-action](https://github.com/bufbuild/buf-setup-action) from 1.14.0 to 1.15.0.
- [Release notes](https://github.com/bufbuild/buf-setup-action/releases)
- [Commits](https://github.com/bufbuild/buf-setup-action/compare/v1.14.0...v1.15.0)

---
updated-dependencies:
- dependency-name: bufbuild/buf-setup-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
(cherry picked from commit e5fab3da5a)

* Rename windows client binary

(cherry picked from commit de09c7fe2b)

* Return IBC packet sequence number (backport #1225) (#1233)

* Return IBC packet sequence number (#1225)

* Return IBC packet sequence number

* Fix review feedbacks

* Remove names to return values in DispatchMsg method

* Fix comments

(cherry picked from commit 4f1c57fc12)

# Conflicts:
#	x/wasm/keeper/handler_plugin.go

* Fix merge conflict

---------

Co-authored-by: pinosu <95283998+pinosu@users.noreply.github.com>
Co-authored-by: Alex Peters <alpe@users.noreply.github.com>

* Test rust panic for regression

(cherry picked from commit a52e604966)

* Fix client checksum verification (#1234)

* Fix client checksum verification

* Review comments

(cherry picked from commit 1a8019b380)

# Conflicts:
#	x/wasm/client/cli/gov_tx.go

* Fix merge conflict

* Fix linters

* Configure sonarcloud analysis

(cherry picked from commit 85cf1614fb)

* Bump bufbuild/buf-setup-action from 1.15.0 to 1.15.1

Bumps [bufbuild/buf-setup-action](https://github.com/bufbuild/buf-setup-action) from 1.15.0 to 1.15.1.
- [Release notes](https://github.com/bufbuild/buf-setup-action/releases)
- [Commits](https://github.com/bufbuild/buf-setup-action/compare/v1.15.0...v1.15.1)

---
updated-dependencies:
- dependency-name: bufbuild/buf-setup-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
(cherry picked from commit 730ea5a1cf)

* Make `CaptureIbcEvents` in ibctesting public.

Before this change, it wasn't possible to implement the
`chain.SendMsgs` method without
[copying](https://github.com/public-awesome/ics721/blob/main/e2e/suite_helpers.go#L81-L98)
them over.

(cherry picked from commit b64fa078a3)

* Upgrade to wasmvm 1.2.1 (backport #1245) (#1254)

* Upgrade to wasmvm 1.2.1 (#1245)

* Use wasmvm store adapter

* Bump wasmvm to v1.2.1

(cherry picked from commit 850f901b2e)

# Conflicts:
#	go.mod
#	go.sum
#	x/wasm/keeper/keeper.go

* Resolve conflicts

---------

Co-authored-by: Alexander Peters <alpe@users.noreply.github.com>

* WIP All cometbft (#1244)

* Dep upgrade; use CometBft

* Remove duplicte message events

* Add changelog for v0.31.0 (#1188)

* Start changelog for v0.31.0

* Add ICA upgrade

* Add proto version link to buf.build

* Update changelog (#1239)

* Update changelog

* Update changelog with latest changes

* Set release date

---------

Co-authored-by: pinosu <95283998+pinosu@users.noreply.github.com>
(cherry picked from commit bc0e817912)

* Remove new message type event

* Support msg update params gov proposal (#1247)

* Add MsgUpdateParams support

* Implement UpdateParams msg

* Fix test UpdateParams

* Add migration test

* Fix

* Fix lint issues

* Revert changes according to review feedback

* Remove more x/params dependencies

* Remove x/params from genesis test

* Formatting

* Restore old changes

* fix lint

* Fix tests and restructure migrations

* Rename alias for convention

---------

Co-authored-by: Alex Peters <alpe@users.noreply.github.com>

* Fix test data generator (#1263)

* linting 47 pr (#1261)

* lint cosmwasm for sdk 47

* fix

* remove setGenesis

* remove additional unused functions

* pass tests

* use SDK's errors module

* unecessary conversions

* unnecessary conversions

* remove unneeded event manager

* complete linting of tests for 47

* add test for reimportation

* check errors

* Update x/wasm/keeper/proposal_integration_test.go

Co-authored-by: Alexander Peters <alpe@users.noreply.github.com>

* apply suggestion

* suggestions

* lints

* don't return error in when making new transactions

* no todo's in the code

* Fix test data generator

* Update x/wasm/types/genesis_test.go

Co-authored-by: Alexander Peters <alpe@users.noreply.github.com>

* use the full string invalid address (2 words) always

---------

Co-authored-by: Alexander Peters <alpe@users.noreply.github.com>

* Regenerate from proto; remove dead code; polish code

* Set SDK version to v0.47x.0 (#1262)

* Set SDK version to v0.47x.0

* Set chainID

* Minor updates

* Set chainID for simulations

* Buf mod update

* Use sdk tag instead of hash in buf

* Bump ibc-go to v7.0.0

* faddat/re merge main (#1274)

undefined

---------

Co-authored-by: vuong <nguyenvuong1122000@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: llllllluc <58892938+llllllluc@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Co-authored-by: Gjermund Garaba <gjermund@garaba.net>
Co-authored-by: Nikhil Suri <nikhilsuri@comcast.net>
Co-authored-by: Paul <p22626262@gmail.com>
Co-authored-by: pinosu <95283998+pinosu@users.noreply.github.com>
Co-authored-by: ekez <zekemedley@gmail.com>
Co-authored-by: Jacob Gadikian <jacobgadikian@gmail.com>
2023-03-20 10:32:22 +01:00

740 lines
29 KiB
Go

package keeper
import (
"encoding/json"
"os"
"testing"
wasmvmtypes "github.com/CosmWasm/wasmvm/types"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
sdk "github.com/cosmos/cosmos-sdk/types"
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
distributionkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper"
"github.com/cosmos/cosmos-sdk/x/staking"
stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/CosmWasm/wasmd/x/wasm/keeper/testdata"
wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types"
)
type StakingInitMsg struct {
Name string `json:"name"`
Symbol string `json:"symbol"`
Decimals uint8 `json:"decimals"`
Validator sdk.ValAddress `json:"validator"`
ExitTax sdk.Dec `json:"exit_tax"`
// MinWithdrawal is uint128 encoded as a string (use math.Int?)
MinWithdrawl string `json:"min_withdrawal"`
}
// StakingHandleMsg is used to encode handle messages
type StakingHandleMsg struct {
Transfer *transferPayload `json:"transfer,omitempty"`
Bond *struct{} `json:"bond,omitempty"`
Unbond *unbondPayload `json:"unbond,omitempty"`
Claim *struct{} `json:"claim,omitempty"`
Reinvest *struct{} `json:"reinvest,omitempty"`
Change *testdata.OwnerPayload `json:"change_owner,omitempty"`
}
type transferPayload struct {
Recipient sdk.Address `json:"recipient"`
// uint128 encoded as string
Amount string `json:"amount"`
}
type unbondPayload struct {
// uint128 encoded as string
Amount string `json:"amount"`
}
// StakingQueryMsg is used to encode query messages
type StakingQueryMsg struct {
Balance *addressQuery `json:"balance,omitempty"`
Claims *addressQuery `json:"claims,omitempty"`
TokenInfo *struct{} `json:"token_info,omitempty"`
Investment *struct{} `json:"investment,omitempty"`
}
type addressQuery struct {
Address sdk.AccAddress `json:"address"`
}
type BalanceResponse struct {
Balance string `json:"balance,omitempty"`
}
type ClaimsResponse struct {
Claims string `json:"claims,omitempty"`
}
type TokenInfoResponse struct {
Name string `json:"name"`
Symbol string `json:"symbol"`
Decimals uint8 `json:"decimals"`
}
type InvestmentResponse struct {
TokenSupply string `json:"token_supply"`
StakedTokens sdk.Coin `json:"staked_tokens"`
NominalValue sdk.Dec `json:"nominal_value"`
Owner sdk.AccAddress `json:"owner"`
Validator sdk.ValAddress `json:"validator"`
ExitTax sdk.Dec `json:"exit_tax"`
// MinWithdrawl is uint128 encoded as a string (use math.Int?)
MinWithdrawl string `json:"min_withdrawal"`
}
func TestInitializeStaking(t *testing.T) {
ctx, k := CreateTestInput(t, false, AvailableCapabilities)
accKeeper, stakingKeeper, keeper, bankKeeper := k.AccountKeeper, k.StakingKeeper, k.ContractKeeper, k.BankKeeper
valAddr := addValidator(t, ctx, stakingKeeper, k.Faucet, sdk.NewInt64Coin("stake", 1234567))
ctx = nextBlock(ctx, stakingKeeper)
v, found := stakingKeeper.GetValidator(ctx, valAddr)
assert.True(t, found)
assert.Equal(t, v.GetDelegatorShares(), sdk.NewDec(1234567))
deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000), sdk.NewInt64Coin("stake", 500000))
creator := k.Faucet.NewFundedRandomAccount(ctx, deposit...)
// upload staking derivates code
stakingCode, err := os.ReadFile("./testdata/staking.wasm")
require.NoError(t, err)
stakingID, _, err := keeper.Create(ctx, creator, stakingCode, nil)
require.NoError(t, err)
require.Equal(t, uint64(1), stakingID)
// register to a valid address
initMsg := StakingInitMsg{
Name: "Staking Derivatives",
Symbol: "DRV",
Decimals: 0,
Validator: valAddr,
ExitTax: sdk.MustNewDecFromStr("0.10"),
MinWithdrawl: "100",
}
initBz, err := json.Marshal(&initMsg)
require.NoError(t, err)
stakingAddr, _, err := k.ContractKeeper.Instantiate(ctx, stakingID, creator, nil, initBz, "staking derivates - DRV", nil)
require.NoError(t, err)
require.NotEmpty(t, stakingAddr)
// nothing spent here
checkAccount(t, ctx, accKeeper, bankKeeper, creator, deposit)
// try to register with a validator not on the list and it fails
_, bob := keyPubAddr()
badInitMsg := StakingInitMsg{
Name: "Missing Validator",
Symbol: "MISS",
Decimals: 0,
Validator: sdk.ValAddress(bob),
ExitTax: sdk.MustNewDecFromStr("0.10"),
MinWithdrawl: "100",
}
badBz, err := json.Marshal(&badInitMsg)
require.NoError(t, err)
_, _, err = k.ContractKeeper.Instantiate(ctx, stakingID, creator, nil, badBz, "missing validator", nil)
require.Error(t, err)
// no changes to bonding shares
val, _ := stakingKeeper.GetValidator(ctx, valAddr)
assert.Equal(t, val.GetDelegatorShares(), sdk.NewDec(1234567))
}
type initInfo struct {
valAddr sdk.ValAddress
creator sdk.AccAddress
contractAddr sdk.AccAddress
ctx sdk.Context
accKeeper authkeeper.AccountKeeper
stakingKeeper *stakingkeeper.Keeper
distKeeper distributionkeeper.Keeper
wasmKeeper Keeper
contractKeeper wasmtypes.ContractOpsKeeper
bankKeeper bankkeeper.Keeper
faucet *TestFaucet
}
func initializeStaking(t *testing.T) initInfo {
ctx, k := CreateTestInput(t, false, AvailableCapabilities)
accKeeper, stakingKeeper, keeper, bankKeeper := k.AccountKeeper, k.StakingKeeper, k.WasmKeeper, k.BankKeeper
valAddr := addValidator(t, ctx, stakingKeeper, k.Faucet, sdk.NewInt64Coin("stake", 1000000))
ctx = nextBlock(ctx, stakingKeeper)
v, found := stakingKeeper.GetValidator(ctx, valAddr)
assert.True(t, found)
assert.Equal(t, v.GetDelegatorShares(), sdk.NewDec(1000000))
assert.Equal(t, v.Status, stakingtypes.Bonded)
deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000), sdk.NewInt64Coin("stake", 500000))
creator := k.Faucet.NewFundedRandomAccount(ctx, deposit...)
// upload staking derivates code
stakingCode, err := os.ReadFile("./testdata/staking.wasm")
require.NoError(t, err)
stakingID, _, err := k.ContractKeeper.Create(ctx, creator, stakingCode, nil)
require.NoError(t, err)
require.Equal(t, uint64(1), stakingID)
// register to a valid address
initMsg := StakingInitMsg{
Name: "Staking Derivatives",
Symbol: "DRV",
Decimals: 0,
Validator: valAddr,
ExitTax: sdk.MustNewDecFromStr("0.10"),
MinWithdrawl: "100",
}
initBz, err := json.Marshal(&initMsg)
require.NoError(t, err)
stakingAddr, _, err := k.ContractKeeper.Instantiate(ctx, stakingID, creator, nil, initBz, "staking derivates - DRV", nil)
require.NoError(t, err)
require.NotEmpty(t, stakingAddr)
return initInfo{
valAddr: valAddr,
creator: creator,
contractAddr: stakingAddr,
ctx: ctx,
accKeeper: accKeeper,
stakingKeeper: stakingKeeper,
wasmKeeper: *keeper,
distKeeper: k.DistKeeper,
bankKeeper: bankKeeper,
contractKeeper: k.ContractKeeper,
faucet: k.Faucet,
}
}
func TestBonding(t *testing.T) {
initInfo := initializeStaking(t)
ctx, valAddr, contractAddr := initInfo.ctx, initInfo.valAddr, initInfo.contractAddr
keeper, stakingKeeper, accKeeper, bankKeeper := initInfo.wasmKeeper, initInfo.stakingKeeper, initInfo.accKeeper, initInfo.bankKeeper
// initial checks of bonding state
val, found := stakingKeeper.GetValidator(ctx, valAddr)
require.True(t, found)
initPower := val.GetDelegatorShares()
// bob has 160k, putting 80k into the contract
full := sdk.NewCoins(sdk.NewInt64Coin("stake", 160000))
funds := sdk.NewCoins(sdk.NewInt64Coin("stake", 80000))
bob := initInfo.faucet.NewFundedRandomAccount(ctx, full...)
// check contract state before
assertBalance(t, ctx, keeper, contractAddr, bob, "0")
assertClaims(t, ctx, keeper, contractAddr, bob, "0")
assertSupply(t, ctx, keeper, contractAddr, "0", sdk.NewInt64Coin("stake", 0))
bond := StakingHandleMsg{
Bond: &struct{}{},
}
bondBz, err := json.Marshal(bond)
require.NoError(t, err)
_, err = initInfo.contractKeeper.Execute(ctx, contractAddr, bob, bondBz, funds)
require.NoError(t, err)
// check some account values - the money is on neither account (cuz it is bonded)
checkAccount(t, ctx, accKeeper, bankKeeper, contractAddr, sdk.Coins{})
checkAccount(t, ctx, accKeeper, bankKeeper, bob, funds)
// make sure the proper number of tokens have been bonded
val, _ = stakingKeeper.GetValidator(ctx, valAddr)
finalPower := val.GetDelegatorShares()
assert.Equal(t, sdk.NewInt(80000), finalPower.Sub(initPower).TruncateInt())
// check the delegation itself
d, found := stakingKeeper.GetDelegation(ctx, contractAddr, valAddr)
require.True(t, found)
assert.Equal(t, d.Shares, sdk.MustNewDecFromStr("80000"))
// check we have the desired balance
assertBalance(t, ctx, keeper, contractAddr, bob, "80000")
assertClaims(t, ctx, keeper, contractAddr, bob, "0")
assertSupply(t, ctx, keeper, contractAddr, "80000", sdk.NewInt64Coin("stake", 80000))
}
func TestUnbonding(t *testing.T) {
initInfo := initializeStaking(t)
ctx, valAddr, contractAddr := initInfo.ctx, initInfo.valAddr, initInfo.contractAddr
keeper, stakingKeeper, accKeeper, bankKeeper := initInfo.wasmKeeper, initInfo.stakingKeeper, initInfo.accKeeper, initInfo.bankKeeper
// initial checks of bonding state
val, found := stakingKeeper.GetValidator(ctx, valAddr)
require.True(t, found)
initPower := val.GetDelegatorShares()
// bob has 160k, putting 80k into the contract
full := sdk.NewCoins(sdk.NewInt64Coin("stake", 160000))
funds := sdk.NewCoins(sdk.NewInt64Coin("stake", 80000))
bob := initInfo.faucet.NewFundedRandomAccount(ctx, full...)
bond := StakingHandleMsg{
Bond: &struct{}{},
}
bondBz, err := json.Marshal(bond)
require.NoError(t, err)
_, err = initInfo.contractKeeper.Execute(ctx, contractAddr, bob, bondBz, funds)
require.NoError(t, err)
// update height a bit
ctx = nextBlock(ctx, stakingKeeper)
// now unbond 30k - note that 3k (10%) goes to the owner as a tax, 27k unbonded and available as claims
unbond := StakingHandleMsg{
Unbond: &unbondPayload{
Amount: "30000",
},
}
unbondBz, err := json.Marshal(unbond)
require.NoError(t, err)
_, err = initInfo.contractKeeper.Execute(ctx, contractAddr, bob, unbondBz, nil)
require.NoError(t, err)
// check some account values - the money is on neither account (cuz it is bonded)
// Note: why is this immediate? just test setup?
checkAccount(t, ctx, accKeeper, bankKeeper, contractAddr, sdk.Coins{})
checkAccount(t, ctx, accKeeper, bankKeeper, bob, funds)
// make sure the proper number of tokens have been bonded (80k - 27k = 53k)
val, _ = stakingKeeper.GetValidator(ctx, valAddr)
finalPower := val.GetDelegatorShares()
assert.Equal(t, sdk.NewInt(53000), finalPower.Sub(initPower).TruncateInt(), finalPower.String())
// check the delegation itself
d, found := stakingKeeper.GetDelegation(ctx, contractAddr, valAddr)
require.True(t, found)
assert.Equal(t, d.Shares, sdk.MustNewDecFromStr("53000"))
// check there is unbonding in progress
un, found := stakingKeeper.GetUnbondingDelegation(ctx, contractAddr, valAddr)
require.True(t, found)
require.Equal(t, 1, len(un.Entries))
assert.Equal(t, "27000", un.Entries[0].Balance.String())
// check we have the desired balance
assertBalance(t, ctx, keeper, contractAddr, bob, "50000")
assertBalance(t, ctx, keeper, contractAddr, initInfo.creator, "3000")
assertClaims(t, ctx, keeper, contractAddr, bob, "27000")
assertSupply(t, ctx, keeper, contractAddr, "53000", sdk.NewInt64Coin("stake", 53000))
}
func TestReinvest(t *testing.T) {
initInfo := initializeStaking(t)
ctx, valAddr, contractAddr := initInfo.ctx, initInfo.valAddr, initInfo.contractAddr
keeper, stakingKeeper, accKeeper, bankKeeper := initInfo.wasmKeeper, initInfo.stakingKeeper, initInfo.accKeeper, initInfo.bankKeeper
distKeeper := initInfo.distKeeper
// initial checks of bonding state
val, found := stakingKeeper.GetValidator(ctx, valAddr)
require.True(t, found)
initPower := val.GetDelegatorShares()
assert.Equal(t, val.Tokens, sdk.NewInt(1000000), "%s", val.Tokens)
// full is 2x funds, 1x goes to the contract, other stays on his wallet
full := sdk.NewCoins(sdk.NewInt64Coin("stake", 400000))
funds := sdk.NewCoins(sdk.NewInt64Coin("stake", 200000))
bob := initInfo.faucet.NewFundedRandomAccount(ctx, full...)
// we will stake 200k to a validator with 1M self-bond
// this means we should get 1/6 of the rewards
bond := StakingHandleMsg{
Bond: &struct{}{},
}
bondBz, err := json.Marshal(bond)
require.NoError(t, err)
_, err = initInfo.contractKeeper.Execute(ctx, contractAddr, bob, bondBz, funds)
require.NoError(t, err)
// update height a bit to solidify the delegation
ctx = nextBlock(ctx, stakingKeeper)
// we get 1/6, our share should be 40k minus 10% commission = 36k
setValidatorRewards(ctx, stakingKeeper, distKeeper, valAddr, "240000")
// this should withdraw our outstanding 36k of rewards and reinvest them in the same delegation
reinvest := StakingHandleMsg{
Reinvest: &struct{}{},
}
reinvestBz, err := json.Marshal(reinvest)
require.NoError(t, err)
_, err = initInfo.contractKeeper.Execute(ctx, contractAddr, bob, reinvestBz, nil)
require.NoError(t, err)
// check some account values - the money is on neither account (cuz it is bonded)
// Note: why is this immediate? just test setup?
checkAccount(t, ctx, accKeeper, bankKeeper, contractAddr, sdk.Coins{})
checkAccount(t, ctx, accKeeper, bankKeeper, bob, funds)
// check the delegation itself
d, found := stakingKeeper.GetDelegation(ctx, contractAddr, valAddr)
require.True(t, found)
// we started with 200k and added 36k
assert.Equal(t, d.Shares, sdk.MustNewDecFromStr("236000"))
// make sure the proper number of tokens have been bonded (80k + 40k = 120k)
val, _ = stakingKeeper.GetValidator(ctx, valAddr)
finalPower := val.GetDelegatorShares()
assert.Equal(t, sdk.NewInt(236000), finalPower.Sub(initPower).TruncateInt(), finalPower.String())
// check there is no unbonding in progress
un, found := stakingKeeper.GetUnbondingDelegation(ctx, contractAddr, valAddr)
assert.False(t, found, "%#v", un)
// check we have the desired balance
assertBalance(t, ctx, keeper, contractAddr, bob, "200000")
assertBalance(t, ctx, keeper, contractAddr, initInfo.creator, "0")
assertClaims(t, ctx, keeper, contractAddr, bob, "0")
assertSupply(t, ctx, keeper, contractAddr, "200000", sdk.NewInt64Coin("stake", 236000))
}
func TestQueryStakingInfo(t *testing.T) {
// STEP 1: take a lot of setup from TestReinvest so we have non-zero info
initInfo := initializeStaking(t)
ctx, valAddr, contractAddr := initInfo.ctx, initInfo.valAddr, initInfo.contractAddr
keeper, stakingKeeper := initInfo.wasmKeeper, initInfo.stakingKeeper
distKeeper := initInfo.distKeeper
// initial checks of bonding state
val, found := stakingKeeper.GetValidator(ctx, valAddr)
require.True(t, found)
assert.Equal(t, sdk.NewInt(1000000), val.Tokens)
// full is 2x funds, 1x goes to the contract, other stays on his wallet
full := sdk.NewCoins(sdk.NewInt64Coin("stake", 400000))
funds := sdk.NewCoins(sdk.NewInt64Coin("stake", 200000))
bob := initInfo.faucet.NewFundedRandomAccount(ctx, full...)
// we will stake 200k to a validator with 1M self-bond
// this means we should get 1/6 of the rewards
bond := StakingHandleMsg{
Bond: &struct{}{},
}
bondBz, err := json.Marshal(bond)
require.NoError(t, err)
_, err = initInfo.contractKeeper.Execute(ctx, contractAddr, bob, bondBz, funds)
require.NoError(t, err)
// update height a bit to solidify the delegation
ctx = nextBlock(ctx, stakingKeeper)
// we get 1/6, our share should be 40k minus 10% commission = 36k
setValidatorRewards(ctx, stakingKeeper, distKeeper, valAddr, "240000")
// see what the current rewards are
origReward := distKeeper.GetValidatorCurrentRewards(ctx, valAddr)
// STEP 2: Prepare the mask contract
deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
creator := initInfo.faucet.NewFundedRandomAccount(ctx, deposit...)
// upload mask code
maskID, _, err := initInfo.contractKeeper.Create(ctx, creator, testdata.ReflectContractWasm(), nil)
require.NoError(t, err)
require.Equal(t, uint64(2), maskID)
// creator instantiates a contract and gives it tokens
maskAddr, _, err := initInfo.contractKeeper.Instantiate(ctx, maskID, creator, nil, []byte("{}"), "mask contract 2", nil)
require.NoError(t, err)
require.NotEmpty(t, maskAddr)
// STEP 3: now, let's reflect some queries.
// let's get the bonded denom
reflectBondedQuery := testdata.ReflectQueryMsg{Chain: &testdata.ChainQuery{Request: &wasmvmtypes.QueryRequest{Staking: &wasmvmtypes.StakingQuery{
BondedDenom: &struct{}{},
}}}}
reflectBondedBin := buildReflectQuery(t, &reflectBondedQuery)
res, err := keeper.QuerySmart(ctx, maskAddr, reflectBondedBin)
require.NoError(t, err)
// first we pull out the data from chain response, before parsing the original response
var reflectRes testdata.ChainResponse
mustParse(t, res, &reflectRes)
var bondedRes wasmvmtypes.BondedDenomResponse
mustParse(t, reflectRes.Data, &bondedRes)
assert.Equal(t, "stake", bondedRes.Denom)
// now, let's reflect a smart query into the x/wasm handlers and see if we get the same result
reflectAllValidatorsQuery := testdata.ReflectQueryMsg{Chain: &testdata.ChainQuery{Request: &wasmvmtypes.QueryRequest{Staking: &wasmvmtypes.StakingQuery{
AllValidators: &wasmvmtypes.AllValidatorsQuery{},
}}}}
reflectAllValidatorsBin := buildReflectQuery(t, &reflectAllValidatorsQuery)
res, err = keeper.QuerySmart(ctx, maskAddr, reflectAllValidatorsBin)
require.NoError(t, err)
// first we pull out the data from chain response, before parsing the original response
mustParse(t, res, &reflectRes)
var allValidatorsRes wasmvmtypes.AllValidatorsResponse
mustParse(t, reflectRes.Data, &allValidatorsRes)
require.Len(t, allValidatorsRes.Validators, 1, string(res))
valInfo := allValidatorsRes.Validators[0]
// Note: this ValAddress not AccAddress, may change with #264
require.Equal(t, valAddr.String(), valInfo.Address)
require.Contains(t, valInfo.Commission, "0.100")
require.Contains(t, valInfo.MaxCommission, "0.200")
require.Contains(t, valInfo.MaxChangeRate, "0.010")
// find a validator
reflectValidatorQuery := testdata.ReflectQueryMsg{Chain: &testdata.ChainQuery{Request: &wasmvmtypes.QueryRequest{Staking: &wasmvmtypes.StakingQuery{
Validator: &wasmvmtypes.ValidatorQuery{
Address: valAddr.String(),
},
}}}}
reflectValidatorBin := buildReflectQuery(t, &reflectValidatorQuery)
res, err = keeper.QuerySmart(ctx, maskAddr, reflectValidatorBin)
require.NoError(t, err)
// first we pull out the data from chain response, before parsing the original response
mustParse(t, res, &reflectRes)
var validatorRes wasmvmtypes.ValidatorResponse
mustParse(t, reflectRes.Data, &validatorRes)
require.NotNil(t, validatorRes.Validator)
valInfo = *validatorRes.Validator
// Note: this ValAddress not AccAddress, may change with #264
require.Equal(t, valAddr.String(), valInfo.Address)
require.Contains(t, valInfo.Commission, "0.100")
require.Contains(t, valInfo.MaxCommission, "0.200")
require.Contains(t, valInfo.MaxChangeRate, "0.010")
// missing validator
noVal := sdk.ValAddress(secp256k1.GenPrivKey().PubKey().Address())
reflectNoValidatorQuery := testdata.ReflectQueryMsg{Chain: &testdata.ChainQuery{Request: &wasmvmtypes.QueryRequest{Staking: &wasmvmtypes.StakingQuery{
Validator: &wasmvmtypes.ValidatorQuery{
Address: noVal.String(),
},
}}}}
reflectNoValidatorBin := buildReflectQuery(t, &reflectNoValidatorQuery)
res, err = keeper.QuerySmart(ctx, maskAddr, reflectNoValidatorBin)
require.NoError(t, err)
// first we pull out the data from chain response, before parsing the original response
mustParse(t, res, &reflectRes)
var noValidatorRes wasmvmtypes.ValidatorResponse
mustParse(t, reflectRes.Data, &noValidatorRes)
require.Nil(t, noValidatorRes.Validator)
// test to get all my delegations
reflectAllDelegationsQuery := testdata.ReflectQueryMsg{Chain: &testdata.ChainQuery{Request: &wasmvmtypes.QueryRequest{Staking: &wasmvmtypes.StakingQuery{
AllDelegations: &wasmvmtypes.AllDelegationsQuery{
Delegator: contractAddr.String(),
},
}}}}
reflectAllDelegationsBin := buildReflectQuery(t, &reflectAllDelegationsQuery)
res, err = keeper.QuerySmart(ctx, maskAddr, reflectAllDelegationsBin)
require.NoError(t, err)
// first we pull out the data from chain response, before parsing the original response
mustParse(t, res, &reflectRes)
var allDelegationsRes wasmvmtypes.AllDelegationsResponse
mustParse(t, reflectRes.Data, &allDelegationsRes)
require.Len(t, allDelegationsRes.Delegations, 1)
delInfo := allDelegationsRes.Delegations[0]
// Note: this ValAddress not AccAddress, may change with #264
require.Equal(t, valAddr.String(), delInfo.Validator)
// note this is not bob (who staked to the contract), but the contract itself
require.Equal(t, contractAddr.String(), delInfo.Delegator)
// this is a different Coin type, with String not BigInt, compare field by field
require.Equal(t, funds[0].Denom, delInfo.Amount.Denom)
require.Equal(t, funds[0].Amount.String(), delInfo.Amount.Amount)
// test to get one delegation
reflectDelegationQuery := testdata.ReflectQueryMsg{Chain: &testdata.ChainQuery{Request: &wasmvmtypes.QueryRequest{Staking: &wasmvmtypes.StakingQuery{
Delegation: &wasmvmtypes.DelegationQuery{
Validator: valAddr.String(),
Delegator: contractAddr.String(),
},
}}}}
reflectDelegationBin := buildReflectQuery(t, &reflectDelegationQuery)
res, err = keeper.QuerySmart(ctx, maskAddr, reflectDelegationBin)
require.NoError(t, err)
// first we pull out the data from chain response, before parsing the original response
mustParse(t, res, &reflectRes)
var delegationRes wasmvmtypes.DelegationResponse
mustParse(t, reflectRes.Data, &delegationRes)
assert.NotEmpty(t, delegationRes.Delegation)
delInfo2 := delegationRes.Delegation
// Note: this ValAddress not AccAddress, may change with #264
require.Equal(t, valAddr.String(), delInfo2.Validator)
// note this is not bob (who staked to the contract), but the contract itself
require.Equal(t, contractAddr.String(), delInfo2.Delegator)
// this is a different Coin type, with String not BigInt, compare field by field
require.Equal(t, funds[0].Denom, delInfo2.Amount.Denom)
require.Equal(t, funds[0].Amount.String(), delInfo2.Amount.Amount)
require.Equal(t, wasmvmtypes.NewCoin(200000, "stake"), delInfo2.CanRedelegate)
require.Len(t, delInfo2.AccumulatedRewards, 1)
// see bonding above to see how we calculate 36000 (240000 / 6 - 10% commission)
require.Equal(t, wasmvmtypes.NewCoin(36000, "stake"), delInfo2.AccumulatedRewards[0])
// ensure rewards did not change when querying (neither amount nor period)
finalReward := distKeeper.GetValidatorCurrentRewards(ctx, valAddr)
require.Equal(t, origReward, finalReward)
}
func TestQueryStakingPlugin(t *testing.T) {
// STEP 1: take a lot of setup from TestReinvest so we have non-zero info
initInfo := initializeStaking(t)
ctx, valAddr, contractAddr := initInfo.ctx, initInfo.valAddr, initInfo.contractAddr
stakingKeeper := initInfo.stakingKeeper
distKeeper := initInfo.distKeeper
// initial checks of bonding state
val, found := stakingKeeper.GetValidator(ctx, valAddr)
require.True(t, found)
assert.Equal(t, sdk.NewInt(1000000), val.Tokens)
// full is 2x funds, 1x goes to the contract, other stays on his wallet
full := sdk.NewCoins(sdk.NewInt64Coin("stake", 400000))
funds := sdk.NewCoins(sdk.NewInt64Coin("stake", 200000))
bob := initInfo.faucet.NewFundedRandomAccount(ctx, full...)
// we will stake 200k to a validator with 1M self-bond
// this means we should get 1/6 of the rewards
bond := StakingHandleMsg{
Bond: &struct{}{},
}
bondBz, err := json.Marshal(bond)
require.NoError(t, err)
_, err = initInfo.contractKeeper.Execute(ctx, contractAddr, bob, bondBz, funds)
require.NoError(t, err)
// update height a bit to solidify the delegation
ctx = nextBlock(ctx, stakingKeeper)
// we get 1/6, our share should be 40k minus 10% commission = 36k
setValidatorRewards(ctx, stakingKeeper, distKeeper, valAddr, "240000")
// see what the current rewards are
origReward := distKeeper.GetValidatorCurrentRewards(ctx, valAddr)
// Step 2: Try out the query plugins
query := wasmvmtypes.StakingQuery{
Delegation: &wasmvmtypes.DelegationQuery{
Delegator: contractAddr.String(),
Validator: valAddr.String(),
},
}
raw, err := StakingQuerier(stakingKeeper, distributionkeeper.NewQuerier(distKeeper))(ctx, &query)
require.NoError(t, err)
var res wasmvmtypes.DelegationResponse
mustParse(t, raw, &res)
assert.NotEmpty(t, res.Delegation)
delInfo := res.Delegation
// Note: this ValAddress not AccAddress, may change with #264
require.Equal(t, valAddr.String(), delInfo.Validator)
// note this is not bob (who staked to the contract), but the contract itself
require.Equal(t, contractAddr.String(), delInfo.Delegator)
// this is a different Coin type, with String not BigInt, compare field by field
require.Equal(t, funds[0].Denom, delInfo.Amount.Denom)
require.Equal(t, funds[0].Amount.String(), delInfo.Amount.Amount)
require.Equal(t, wasmvmtypes.NewCoin(200000, "stake"), delInfo.CanRedelegate)
require.Len(t, delInfo.AccumulatedRewards, 1)
// see bonding above to see how we calculate 36000 (240000 / 6 - 10% commission)
require.Equal(t, wasmvmtypes.NewCoin(36000, "stake"), delInfo.AccumulatedRewards[0])
// ensure rewards did not change when querying (neither amount nor period)
finalReward := distKeeper.GetValidatorCurrentRewards(ctx, valAddr)
require.Equal(t, origReward, finalReward)
}
// adds a few validators and returns a list of validators that are registered
func addValidator(t *testing.T, ctx sdk.Context, stakingKeeper *stakingkeeper.Keeper, faucet *TestFaucet, value sdk.Coin) sdk.ValAddress {
owner := faucet.NewFundedRandomAccount(ctx, value)
privKey := secp256k1.GenPrivKey()
pubKey := privKey.PubKey()
addr := sdk.ValAddress(pubKey.Address())
pkAny, err := codectypes.NewAnyWithValue(pubKey)
require.NoError(t, err)
msg := &stakingtypes.MsgCreateValidator{
Description: stakingtypes.Description{
Moniker: "Validator power",
},
Commission: stakingtypes.CommissionRates{
Rate: sdk.MustNewDecFromStr("0.1"),
MaxRate: sdk.MustNewDecFromStr("0.2"),
MaxChangeRate: sdk.MustNewDecFromStr("0.01"),
},
MinSelfDelegation: sdk.OneInt(),
DelegatorAddress: owner.String(),
ValidatorAddress: addr.String(),
Pubkey: pkAny,
Value: value,
}
_, err = stakingkeeper.NewMsgServerImpl(stakingKeeper).CreateValidator(sdk.WrapSDKContext(ctx), msg)
require.NoError(t, err)
return addr
}
// this will commit the current set, update the block height and set historic info
// basically, letting two blocks pass
func nextBlock(ctx sdk.Context, stakingKeeper *stakingkeeper.Keeper) sdk.Context {
staking.EndBlocker(ctx, stakingKeeper)
ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1)
staking.BeginBlocker(ctx, stakingKeeper)
return ctx
}
func setValidatorRewards(ctx sdk.Context, stakingKeeper *stakingkeeper.Keeper, distKeeper distributionkeeper.Keeper, valAddr sdk.ValAddress, reward string) {
// allocate some rewards
vali := stakingKeeper.Validator(ctx, valAddr)
amount, err := sdk.NewDecFromStr(reward)
if err != nil {
panic(err)
}
payout := sdk.DecCoins{{Denom: "stake", Amount: amount}}
distKeeper.AllocateTokensToValidator(ctx, vali, payout)
}
func assertBalance(t *testing.T, ctx sdk.Context, keeper Keeper, contract sdk.AccAddress, addr sdk.AccAddress, expected string) {
query := StakingQueryMsg{
Balance: &addressQuery{
Address: addr,
},
}
queryBz, err := json.Marshal(query)
require.NoError(t, err)
res, err := keeper.QuerySmart(ctx, contract, queryBz)
require.NoError(t, err)
var balance BalanceResponse
err = json.Unmarshal(res, &balance)
require.NoError(t, err)
assert.Equal(t, expected, balance.Balance)
}
func assertClaims(t *testing.T, ctx sdk.Context, keeper Keeper, contract sdk.AccAddress, addr sdk.AccAddress, expected string) {
query := StakingQueryMsg{
Claims: &addressQuery{
Address: addr,
},
}
queryBz, err := json.Marshal(query)
require.NoError(t, err)
res, err := keeper.QuerySmart(ctx, contract, queryBz)
require.NoError(t, err)
var claims ClaimsResponse
err = json.Unmarshal(res, &claims)
require.NoError(t, err)
assert.Equal(t, expected, claims.Claims)
}
func assertSupply(t *testing.T, ctx sdk.Context, keeper Keeper, contract sdk.AccAddress, expectedIssued string, expectedBonded sdk.Coin) {
query := StakingQueryMsg{Investment: &struct{}{}}
queryBz, err := json.Marshal(query)
require.NoError(t, err)
res, err := keeper.QuerySmart(ctx, contract, queryBz)
require.NoError(t, err)
var invest InvestmentResponse
err = json.Unmarshal(res, &invest)
require.NoError(t, err)
assert.Equal(t, expectedIssued, invest.TokenSupply)
assert.Equal(t, expectedBonded, invest.StakedTokens)
}