Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore!: align staking module with mainline SDK #339

Merged
merged 4 commits into from
Aug 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions client/flags/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,6 @@ const (
// Tendermint logging flags
FlagLogLevel = "log_level"
FlagLogFormat = "log_format"

// QGB related flags
FlagEVMAddress = "evm-address"
)

// LineBreak can be included in a command list to provide a blank line
Expand Down
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ require (
github.com/cosmos/gogoproto v1.4.10
github.com/cosmos/iavl v0.19.6
github.com/cosmos/ledger-cosmos-go v0.12.2
github.com/ethereum/go-ethereum v1.10.17
github.com/gogo/gateway v1.1.0
github.com/gogo/protobuf v1.3.2
github.com/golang/mock v1.6.0
Expand Down
1 change: 0 additions & 1 deletion go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,6 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ethereum/go-ethereum v1.10.17 h1:XEcumY+qSr1cZQaWsQs5Kck3FHB0V2RiMHPdTBJ+oT8=
github.com/ethereum/go-ethereum v1.10.17/go.mod h1:Lt5WzjM07XlXc95YzrhosmR4J9Ahd6X2wyEV2SvGhk0=
github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c h1:8ISkoahWXwZR41ois5lSJBSVw4D0OV19Ht/JSTzvSv0=
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A=
Expand Down
3 changes: 0 additions & 3 deletions proto/cosmos/staking/v1beta1/staking.proto
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@
// bond shares is based on the amount of coins delegated divided by the current
// exchange rate. Voting power can be calculated as total bonded shares
// multiplied by exchange rate.
message Validator {

Check failure on line 86 in proto/cosmos/staking/v1beta1/staking.proto

View workflow job for this annotation

GitHub Actions / break-check

Previously present field "12" with name "evm_address" on message "Validator" was deleted.
option (gogoproto.equal) = false;
option (gogoproto.goproto_stringer) = false;
option (gogoproto.goproto_getters) = false;
Expand Down Expand Up @@ -124,9 +124,6 @@
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
];
// This is a hex encoded 0x EVM public key that will be used by this
// validator on the target EVM chain.
string evm_address = 12;
}

// BondStatus is the status of a validator.
Expand Down
10 changes: 3 additions & 7 deletions proto/cosmos/staking/v1beta1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
}

// MsgCreateValidator defines a SDK message for creating a new validator.
message MsgCreateValidator {

Check failure on line 44 in proto/cosmos/staking/v1beta1/tx.proto

View workflow job for this annotation

GitHub Actions / break-check

Previously present field "8" with name "evm_address" on message "MsgCreateValidator" was deleted.
// NOTE(fdymylja): this is a particular case in which
// if validator_address == delegator_address then only one
// is expected to sign, otherwise both are.
Expand All @@ -62,16 +62,13 @@
string validator_address = 5 [(cosmos_proto.scalar) = "cosmos.AddressString"];
google.protobuf.Any pubkey = 6 [(cosmos_proto.accepts_interface) = "cosmos.crypto.PubKey"];
cosmos.base.v1beta1.Coin value = 7 [(gogoproto.nullable) = false];
// This is a hex encoded 0x EVM public key that will be used by this
// validator on the target EVM chain.
string evm_address = 8;
}

// MsgCreateValidatorResponse defines the Msg/CreateValidator response type.
message MsgCreateValidatorResponse {}

// MsgEditValidator defines a SDK message for editing an existing validator.
message MsgEditValidator {

Check failure on line 71 in proto/cosmos/staking/v1beta1/tx.proto

View workflow job for this annotation

GitHub Actions / break-check

Previously present field "5" with name "evm_address" on message "MsgEditValidator" was deleted.
option (cosmos.msg.v1.signer) = "validator_address";

option (gogoproto.equal) = false;
Expand All @@ -88,7 +85,6 @@
[(cosmos_proto.scalar) = "cosmos.Dec", (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec"];
string min_self_delegation = 4
[(cosmos_proto.scalar) = "cosmos.Int", (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int"];
string evm_address = 5;
}

// MsgEditValidatorResponse defines the Msg/EditValidator response type.
Expand Down Expand Up @@ -151,10 +147,10 @@
option (cosmos.msg.v1.signer) = "delegator_address";
option (gogoproto.equal) = false;

string delegator_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
string validator_address = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"];
string delegator_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
string validator_address = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"];
// amount is always less than or equal to unbonding delegation entry balance
cosmos.base.v1beta1.Coin amount = 3 [(gogoproto.nullable) = false];
cosmos.base.v1beta1.Coin amount = 3 [(gogoproto.nullable) = false];
// creation_height is the height which the unbonding took place.
int64 creation_height = 4;
}
Expand Down
9 changes: 1 addition & 8 deletions simapp/simd/cmd/testnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import (
"os"
"path/filepath"

"github.com/cosmos/cosmos-sdk/x/staking/teststaking"

"github.com/spf13/cobra"
tmconfig "github.com/tendermint/tendermint/config"
tmos "github.com/tendermint/tendermint/libs/os"
Expand Down Expand Up @@ -289,19 +287,14 @@ func initTestnetFiles(
genBalances = append(genBalances, banktypes.Balance{Address: addr.String(), Coins: coins.Sort()})
genAccounts = append(genAccounts, authtypes.NewBaseAccount(addr, nil, 0, 0))

evmAddress, err := teststaking.RandomEVMAddress()
if err != nil {
return err
}

valTokens := sdk.TokensFromConsensusPower(100, sdk.DefaultPowerReduction)
createValMsg, err := stakingtypes.NewMsgCreateValidator(
sdk.ValAddress(addr),
valPubKeys[i],
sdk.NewCoin(sdk.DefaultBondDenom, valTokens),
stakingtypes.NewDescription(nodeDirName, "", "", "", ""),
stakingtypes.NewCommissionRates(sdk.OneDec(), sdk.OneDec(), sdk.OneDec()),
sdk.OneInt(), *evmAddress,
sdk.OneInt(),
)
if err != nil {
return err
Expand Down
48 changes: 13 additions & 35 deletions testutil/network/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package network
import (
"bufio"
"context"
"crypto/ecdsa"
"encoding/json"
"errors"
"fmt"
Expand All @@ -16,10 +15,7 @@ import (
"testing"
"time"

"github.com/ethereum/go-ethereum/crypto"

"cosmossdk.io/math"
"github.com/ethereum/go-ethereum/common"
"github.com/rs/zerolog"
"github.com/spf13/cobra"
tmrand "github.com/tendermint/tendermint/libs/rand"
Expand Down Expand Up @@ -172,9 +168,6 @@ type (
api *api.Server
grpc *grpc.Server
grpcWeb *http.Server

EVMPrivateKey *ecdsa.PrivateKey
EVMAddr common.Address
}
)

Expand Down Expand Up @@ -407,21 +400,13 @@ func New(l Logger, baseDir string, cfg Config) (*Network, error) {
return nil, err
}

evmPrivateKey, err := crypto.GenerateKey()
if err != nil {
return nil, err
}
orchEVMPublicKey := evmPrivateKey.Public().(*ecdsa.PublicKey)
evmAddr := crypto.PubkeyToAddress(*orchEVMPublicKey)

createValMsg, err := stakingtypes.NewMsgCreateValidator(
sdk.ValAddress(addr),
valPubKeys[i],
sdk.NewCoin(cfg.BondDenom, cfg.BondedTokens),
stakingtypes.NewDescription(nodeDirName, "", "", "", ""),
stakingtypes.NewCommissionRates(commission, sdk.OneDec(), sdk.OneDec()),
sdk.OneInt(),
evmAddr,
)
if err != nil {
return nil, err
Expand Down Expand Up @@ -478,20 +463,18 @@ func New(l Logger, baseDir string, cfg Config) (*Network, error) {
WithAccountRetriever(cfg.AccountRetriever)

network.Validators[i] = &Validator{
AppConfig: appCfg,
ClientCtx: clientCtx,
Ctx: ctx,
Dir: filepath.Join(network.BaseDir, nodeDirName),
NodeID: nodeID,
PubKey: pubKey,
Moniker: nodeDirName,
RPCAddress: tmCfg.RPC.ListenAddress,
P2PAddress: tmCfg.P2P.ListenAddress,
APIAddress: apiAddr,
Address: addr,
ValAddress: sdk.ValAddress(addr),
EVMPrivateKey: evmPrivateKey,
EVMAddr: evmAddr,
AppConfig: appCfg,
ClientCtx: clientCtx,
Ctx: ctx,
Dir: filepath.Join(network.BaseDir, nodeDirName),
NodeID: nodeID,
PubKey: pubKey,
Moniker: nodeDirName,
RPCAddress: tmCfg.RPC.ListenAddress,
P2PAddress: tmCfg.P2P.ListenAddress,
APIAddress: apiAddr,
Address: addr,
ValAddress: sdk.ValAddress(addr),
}
}

Expand Down Expand Up @@ -546,12 +529,7 @@ func (n *Network) LatestHeight() (int64, error) {
// committed after a given block. If that height is not reached within a timeout,
// an error is returned. Regardless, the latest height queried is returned.
func (n *Network) WaitForHeight(h int64) (int64, error) {
timeout := 10 * n.Config.TimeoutCommit
if timeout < 15*time.Second {
timeout = 15 * time.Second
}

return n.WaitForHeightWithTimeout(h, timeout)
return n.WaitForHeightWithTimeout(h, 10*time.Second)
}

// WaitForHeightWithTimeout is the same as WaitForHeight except the caller can
Expand Down
7 changes: 1 addition & 6 deletions x/auth/migrations/v043/store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import (
"testing"
"time"

"github.com/cosmos/cosmos-sdk/x/staking/teststaking"

"github.com/stretchr/testify/require"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"

Expand Down Expand Up @@ -654,9 +652,6 @@ func createValidator(t *testing.T, ctx sdk.Context, app *simapp.SimApp, powers i
pks := simapp.CreateTestPubKeys(1)
cdc := simapp.MakeTestEncodingConfig().Codec

evmAddr, err := teststaking.RandomEVMAddress()
require.NoError(t, err)

app.StakingKeeper = stakingkeeper.NewKeeper(
cdc,
app.GetKey(stakingtypes.StoreKey),
Expand All @@ -665,7 +660,7 @@ func createValidator(t *testing.T, ctx sdk.Context, app *simapp.SimApp, powers i
app.GetSubspace(stakingtypes.ModuleName),
)

val1, err := stakingtypes.NewValidator(valAddrs[0], pks[0], stakingtypes.Description{}, *evmAddr)
val1, err := stakingtypes.NewValidator(valAddrs[0], pks[0], stakingtypes.Description{})
require.NoError(t, err)

app.StakingKeeper.SetValidator(ctx, val1)
Expand Down
6 changes: 2 additions & 4 deletions x/distribution/abci_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,7 @@ func TestVerifyProposerRewardAssignement(t *testing.T) {
validators[i].addr = sdk.ValAddress(addrs[i])
validators[i].pubkey = ed25519.GenPrivKey().PubKey()
validators[i].votes = make([]abci.VoteInfo, totalValidators)
randomEVMAddress, err := teststaking.RandomEVMAddress()
require.NoError(t, err)
tstaking.CreateValidatorWithValPower(validators[i].addr, validators[i].pubkey, power, *randomEVMAddress, true)
tstaking.CreateValidatorWithValPower(validators[i].addr, validators[i].pubkey, power, true)
}
app.EndBlock(abci.RequestEndBlock{})
require.NotEmpty(t, app.Commit())
Expand Down Expand Up @@ -104,6 +102,6 @@ func TestVerifyProposerRewardAssignement(t *testing.T) {
rewardsValidatorBeforeLazyValidator := app.DistrKeeper.GetValidatorOutstandingRewardsCoins(ctx, validators[lazyValidatorIdx+1].addr)
rewardsLazyValidator := app.DistrKeeper.GetValidatorOutstandingRewardsCoins(ctx, validators[lazyValidatorIdx].addr)
rewardsValidatorAfterLazyValidator := app.DistrKeeper.GetValidatorOutstandingRewardsCoins(ctx, validators[lazyValidatorIdx+1].addr)
require.True(t, rewardsLazyValidator[0].Amount.Equal(rewardsValidatorAfterLazyValidator[0].Amount))
require.True(t, rewardsLazyValidator[0].Amount.LT(rewardsValidatorAfterLazyValidator[0].Amount))
require.Equal(t, rewardsValidatorBeforeLazyValidator, rewardsValidatorAfterLazyValidator)
}
6 changes: 3 additions & 3 deletions x/distribution/client/testutil/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,13 @@ func (s *IntegrationTestSuite) TestGetCmdQueryParams() {
{
"json output",
[]string{fmt.Sprintf("--%s=json", tmcli.OutputFlag)},
`{"community_tax":"0.020000000000000000","base_proposer_reward":"0.000000000000000000","bonus_proposer_reward":"0.000000000000000000","withdraw_addr_enabled":true}`,
`{"community_tax":"0.020000000000000000","base_proposer_reward":"0.010000000000000000","bonus_proposer_reward":"0.040000000000000000","withdraw_addr_enabled":true}`,
},
{
"text output",
[]string{fmt.Sprintf("--%s=text", tmcli.OutputFlag)},
`base_proposer_reward: "0.000000000000000000"
bonus_proposer_reward: "0.000000000000000000"
`base_proposer_reward: "0.010000000000000000"
bonus_proposer_reward: "0.040000000000000000"
community_tax: "0.020000000000000000"
withdraw_addr_enabled: true`,
},
Expand Down
38 changes: 13 additions & 25 deletions x/distribution/keeper/allocation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,12 @@ func TestAllocateTokensToValidatorWithCommission(t *testing.T) {
ctx := app.BaseApp.NewContext(false, tmproto.Header{})

addrs := simapp.AddTestAddrs(app, ctx, 3, sdk.NewInt(1234))
randomEVMAddress, err := teststaking.RandomEVMAddress()
require.NoError(t, err)
valAddrs := simapp.ConvertAddrsToValAddrs(addrs)
tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper)

// create validator with 50% commission
tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0))
tstaking.CreateValidator(sdk.ValAddress(addrs[0]), valConsPk1, sdk.NewInt(100), *randomEVMAddress, true)
tstaking.CreateValidator(sdk.ValAddress(addrs[0]), valConsPk1, sdk.NewInt(100), true)
val := app.StakingKeeper.Validator(ctx, valAddrs[0])

// allocate tokens
Expand All @@ -55,20 +53,16 @@ func TestAllocateTokensToManyValidators(t *testing.T) {
app.DistrKeeper.SetFeePool(ctx, disttypes.InitialFeePool())

addrs := simapp.AddTestAddrs(app, ctx, 2, sdk.NewInt(1234))
randomEVMAddress, err := teststaking.RandomEVMAddress()
require.NoError(t, err)
valAddrs := simapp.ConvertAddrsToValAddrs(addrs)
tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper)

// create validator with 50% commission
tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0))
tstaking.CreateValidator(valAddrs[0], valConsPk1, sdk.NewInt(100), *randomEVMAddress, true)
tstaking.CreateValidator(valAddrs[0], valConsPk1, sdk.NewInt(100), true)

// create second validator with 0% commission
randomEVMAddress2, err := teststaking.RandomEVMAddress()
require.NoError(t, err)
tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDec(0), sdk.NewDec(0), sdk.NewDec(0))
tstaking.CreateValidator(valAddrs[1], valConsPk2, sdk.NewInt(100), *randomEVMAddress2, true)
tstaking.CreateValidator(valAddrs[1], valConsPk2, sdk.NewInt(100), true)

abciValA := abci.Validator{
Address: valConsPk1.Address(),
Expand Down Expand Up @@ -111,18 +105,18 @@ func TestAllocateTokensToManyValidators(t *testing.T) {
app.DistrKeeper.AllocateTokens(ctx, 200, 200, valConsAddr2, votes)

// 98 outstanding rewards (100 less 2 to community pool)
require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(490, 1)}}, app.DistrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[0]).Rewards)
require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(490, 1)}}, app.DistrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[1]).Rewards)
require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(465, 1)}}, app.DistrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[0]).Rewards)
require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(515, 1)}}, app.DistrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[1]).Rewards)
// 2 community pool coins
require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(2)}}, app.DistrKeeper.GetFeePool(ctx).CommunityPool)
// 50% commission for first proposer, (0.5 * 93%) * 100 / 2 = 23.25
require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(2450, 2)}}, app.DistrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission)
require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(2325, 2)}}, app.DistrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission)
// zero commission for second proposer
require.True(t, app.DistrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[1]).Commission.IsZero())
// just staking.proportional for first proposer less commission = (0.5 * 98%) * 100 / 2 = 24.50
require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(2450, 2)}}, app.DistrKeeper.GetValidatorCurrentRewards(ctx, valAddrs[0]).Rewards)
// proposer reward + staking.proportional for second proposer = (0.5 * (98%)) * 100 = 49
require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(490, 1)}}, app.DistrKeeper.GetValidatorCurrentRewards(ctx, valAddrs[1]).Rewards)
// just staking.proportional for first proposer less commission = (0.5 * 93%) * 100 / 2 = 23.25
require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(2325, 2)}}, app.DistrKeeper.GetValidatorCurrentRewards(ctx, valAddrs[0]).Rewards)
// proposer reward + staking.proportional for second proposer = (5 % + 0.5 * (93%)) * 100 = 51.5
require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(515, 1)}}, app.DistrKeeper.GetValidatorCurrentRewards(ctx, valAddrs[1]).Rewards)
}

func TestAllocateTokensTruncation(t *testing.T) {
Expand All @@ -137,22 +131,16 @@ func TestAllocateTokensTruncation(t *testing.T) {
tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper)

// create validator with 10% commission
randomEVMAddress, err := teststaking.RandomEVMAddress()
require.NoError(t, err)
tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(1, 1), sdk.NewDec(0))
tstaking.CreateValidator(valAddrs[0], valConsPk1, sdk.NewInt(110), *randomEVMAddress, true)
tstaking.CreateValidator(valAddrs[0], valConsPk1, sdk.NewInt(110), true)

// create second validator with 10% commission
randomEVMAddress2, err := teststaking.RandomEVMAddress()
require.NoError(t, err)
tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(1, 1), sdk.NewDec(0))
tstaking.CreateValidator(valAddrs[1], valConsPk2, sdk.NewInt(100), *randomEVMAddress2, true)
tstaking.CreateValidator(valAddrs[1], valConsPk2, sdk.NewInt(100), true)

// create third validator with 10% commission
randomEVMAddress3, err := teststaking.RandomEVMAddress()
require.NoError(t, err)
tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(1, 1), sdk.NewDec(0))
tstaking.CreateValidator(valAddrs[2], valConsPk3, sdk.NewInt(100), *randomEVMAddress3, true)
tstaking.CreateValidator(valAddrs[2], valConsPk3, sdk.NewInt(100), true)

abciValA := abci.Validator{
Address: valConsPk1.Address(),
Expand Down
Loading
Loading