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

imp(staking): implement the CreateValidator function for staking precompiled contract #2030

Merged
merged 20 commits into from
Nov 16, 2023
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
2b642e5
imp(staking): add create validator
luchenqun Nov 10, 2023
5a71c74
imp(precompile): implement the createValidator function of precompile…
luchenqun Nov 11, 2023
09bc8d3
chore: update CHANGELOG.md
luchenqun Nov 11, 2023
d86177f
imp(staking): remove pubkey from CreateValidator event
luchenqun Nov 11, 2023
32b6d55
imp(staking): update CreateValidator event
luchenqun Nov 12, 2023
9df6a5e
imp(staking): use abi arguments pack events
luchenqun Nov 13, 2023
edb1355
imp(staking): use json marshal unmarshal validator description and co…
luchenqun Nov 13, 2023
4afa195
imp(staking): only allow users to directly call the StakingI contract…
luchenqun Nov 13, 2023
96b0ad1
imp(staking): update create validator for precompiles
luchenqun Nov 14, 2023
85984df
imp(staking): add CreateValidatorMethod to IsTransaction
luchenqun Nov 14, 2023
502e720
chore: merge main branch
luchenqun Nov 15, 2023
21cd477
Update precompiles/staking/StakingI.sol
fedekunze Nov 15, 2023
cf1dde9
Update precompiles/staking/abi.json
fedekunze Nov 15, 2023
37a42ad
Merge remote-tracking branch 'origin/main' into luke/create-validator
luchenqun Nov 16, 2023
6e6b9f3
imp(staking): update event CreateValidator change string indexed vali…
luchenqun Nov 16, 2023
ff61708
imp(staking): update precompiles NewMsgCreateValidator
luchenqun Nov 16, 2023
3b3fbfc
imp(staking): update CreateValidator event and some optimizations
luchenqun Nov 16, 2023
ded0b58
imp(staking): update precompiles common errors
luchenqun Nov 16, 2023
5c4756f
imp(staking): update precompiles staking tx.go
luchenqun Nov 16, 2023
3804ce0
Merge branch 'main' into luke/create-validator
fedekunze Nov 16, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
- (osmosis-outpost) [#2017](https://github.com/evmos/evmos/pull/2017) Refactor types, errors and precompile struct.
- (erc20) [#2023](https://github.com/evmos/evmos/pull/2023) Add tests for ERC20 precompile queries.
- (osmosis-outpost) [#2025](https://github.com/evmos/evmos/pull/2025) Use a struct to wrap parsed parameters from Solidity.
- (staking) [#2030](https://github.com/evmos/evmos/pull/2030) Implement the `CreateValidator` function for staking precompiled contract.

### Bug Fixes

Expand Down
50 changes: 50 additions & 0 deletions precompiles/staking/StakingI.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,22 @@ address constant STAKING_PRECOMPILE_ADDRESS = 0x00000000000000000000000000000000
StakingI constant STAKING_CONTRACT = StakingI(STAKING_PRECOMPILE_ADDRESS);

/// @dev Define all the available staking methods.
string constant MSG_CREATE_VALIDATOR = "/cosmos.staking.v1beta1.MsgCreateValidator";
string constant MSG_DELEGATE = "/cosmos.staking.v1beta1.MsgDelegate";
string constant MSG_UNDELEGATE = "/cosmos.staking.v1beta1.MsgUndelegate";
string constant MSG_REDELEGATE = "/cosmos.staking.v1beta1.MsgBeginRedelegate";
string constant MSG_CANCEL_UNDELEGATION = "/cosmos.staking.v1beta1.MsgCancelUnbondingDelegation";

/// @dev Defines the initial description to be used for creating
/// a validator.
struct Description {
string moniker;
string identity;
string website;
string securityContact;
string details;
}

/// @dev Defines the initial commission rates to be used for creating
/// a validator.
struct CommissionRates {
Expand Down Expand Up @@ -114,6 +125,25 @@ enum BondStatus {
/// wraps the pallet.
/// @custom:address 0x0000000000000000000000000000000000000800
interface StakingI is authorization.AuthorizationI {
/// @dev Defines a method for creating a new validator.
/// @param description The initial description
/// @param commissionRates The initial commissionRates
/// @param minSelfDelegation The validator's self declared minimum self delegation
/// @param delegatorAddress The delegator address
/// @param validatorAddress The validator address
/// @param pubkey The consensus public key of the validator
/// @param value The amount of the coin to be self delegated to the validator
/// @return success Whether or not the create validator was successful
function createValidator(
Description calldata description,
CommissionRates calldata commissionRates,
uint256 minSelfDelegation,
address delegatorAddress,
string memory validatorAddress,
string memory pubkey,
uint256 value
) external returns (bool success);

/// @dev Defines a method for performing a delegation of coins from a delegator to a validator.
/// @param delegatorAddress The address of the delegator
/// @param validatorAddress The address of the validator
Expand Down Expand Up @@ -238,6 +268,26 @@ interface StakingI is authorization.AuthorizationI {
PageResponse calldata pageResponse
);

/// @dev CreateValidator defines an Event emitted when a create a new validator.
/// @param delegatorAddress The address of the delegator
/// @param validatorAddress The address of the validator
/// @param commissionRate The commission rate charged to delegators, as a fraction
/// @param commissionMaxRate The commission max rate charged to delegators, as a fraction
/// @param commissionMaxChangeRate The commission max change rate charged to delegators, as a fraction
/// @param minSelfDelegation The validator's self declared minimum self delegation
/// @param pubkey The consensus public key of the validator
/// @param value The amount of coin being self delegated
event CreateValidator(
address indexed delegatorAddress,
string indexed validatorAddress,
fedekunze marked this conversation as resolved.
Show resolved Hide resolved
uint256 commissionRate,
uint256 commissionMaxRate,
uint256 commissionMaxChangeRate,
uint256 minSelfDelegation,
string pubkey,
uint256 value
fedekunze marked this conversation as resolved.
Show resolved Hide resolved
);

/// @dev Delegate defines an Event emitted when a given amount of tokens are delegated from the
/// delegator address to the validator address.
/// @param delegatorAddress The address of the delegator
Expand Down
148 changes: 148 additions & 0 deletions precompiles/staking/abi.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,61 @@
"name": "CancelUnbondingDelegation",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "delegatorAddress",
"type": "address"
},
{
"indexed": true,
"internalType": "string",
"name": "validatorAddress",
"type": "string"
fedekunze marked this conversation as resolved.
Show resolved Hide resolved
},
{
"indexed": false,
"internalType": "uint256",
"name": "commissionRate",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "commissionMaxRate",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "commissionMaxChangeRate",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "minSelfDelegation",
"type": "uint256"
},
{
"indexed": false,
"internalType": "string",
"name": "pubkey",
"type": "string"
},
{
"indexed": false,
"internalType": "uint256",
"name": "value",
"type": "uint256"
}
],
"name": "CreateValidator",
"type": "event"
},
{
"anonymous": false,
"inputs": [
Expand Down Expand Up @@ -308,6 +363,99 @@
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "string",
"name": "moniker",
"type": "string"
},
{
"internalType": "string",
"name": "identity",
"type": "string"
},
{
"internalType": "string",
"name": "website",
"type": "string"
},
{
"internalType": "string",
"name": "securityContact",
"type": "string"
},
{
"internalType": "string",
"name": "details",
"type": "string"
}
],
"internalType": "struct Description",
"name": "description",
"type": "tuple"
},
{
"components": [
{
"internalType": "uint256",
"name": "rate",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "maxRate",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "maxChangeRate",
"type": "uint256"
}
],
"internalType": "struct CommissionRates",
"name": "commissionRates",
"type": "tuple"
},
{
"internalType": "uint256",
"name": "minSelfDelegation",
"type": "uint256"
},
{
"internalType": "address",
"name": "delegatorAddress",
"type": "address"
},
{
"internalType": "string",
"name": "validatorAddress",
"type": "string"
},
{
"internalType": "string",
"name": "pubkey",
"type": "string"
},
{
"internalType": "uint256",
"name": "value",
"type": "uint256"
}
],
"name": "createValidator",
"outputs": [
{
"internalType": "bool",
"name": "success",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
Expand Down
42 changes: 42 additions & 0 deletions precompiles/staking/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
)

const (
// EventTypeCreateValidator defines the event type for the staking CreateValidator transaction.
EventTypeCreateValidator = "CreateValidator"
// EventTypeDelegate defines the event type for the staking Delegate transaction.
EventTypeDelegate = "Delegate"
// EventTypeUnbond defines the event type for the staking Undelegate transaction.
Expand Down Expand Up @@ -122,6 +124,46 @@
return nil
}

// EmitCreateValidatorEvent creates a new ctreate valdator event emitted on a CreateValidator transaction.
func (p Precompile) EmitCreateValidatorEvent(ctx sdk.Context, stateDB vm.StateDB, msg *stakingtypes.MsgCreateValidator, delegatorAddr common.Address) error {
// Prepare the event topics
event := p.ABI.Events[EventTypeCreateValidator]
topics, err := p.createStakingTxTopics(3, event, delegatorAddr, msg.ValidatorAddress)
fedekunze marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return err
}

Check warning on line 134 in precompiles/staking/events.go

View check run for this annotation

Codecov / codecov/patch

precompiles/staking/events.go#L128-L134

Added lines #L128 - L134 were not covered by tests

// Pack the arguments to be used as the Data field
arguments := abi.Arguments{
event.Inputs[2],
event.Inputs[3],
event.Inputs[4],
event.Inputs[5],
event.Inputs[6],
event.Inputs[7],
}
packed, err := arguments.Pack(
msg.Commission.Rate.BigInt(),
msg.Commission.MaxRate.BigInt(),
msg.Commission.MaxChangeRate.BigInt(),
msg.MinSelfDelegation.BigInt(),
msg.Pubkey.String(),
msg.Value.Amount.BigInt(),
fedekunze marked this conversation as resolved.
Show resolved Hide resolved
)
if err != nil {
return err
}

Check warning on line 155 in precompiles/staking/events.go

View check run for this annotation

Codecov / codecov/patch

precompiles/staking/events.go#L137-L155

Added lines #L137 - L155 were not covered by tests

stateDB.AddLog(&ethtypes.Log{
Address: p.Address(),
Topics: topics,
Data: packed,
BlockNumber: uint64(ctx.BlockHeight()),
Dismissed Show dismissed Hide dismissed
})

return nil

Check warning on line 164 in precompiles/staking/events.go

View check run for this annotation

Codecov / codecov/patch

precompiles/staking/events.go#L157-L164

Added lines #L157 - L164 were not covered by tests
}

// EmitDelegateEvent creates a new delegate event emitted on a Delegate transaction.
func (p Precompile) EmitDelegateEvent(ctx sdk.Context, stateDB vm.StateDB, msg *stakingtypes.MsgDelegate, delegatorAddr common.Address) error {
valAddr, err := sdk.ValAddressFromBech32(msg.ValidatorAddress)
Expand Down
2 changes: 2 additions & 0 deletions precompiles/staking/staking.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@
case authorization.DecreaseAllowanceMethod:
bz, err = p.DecreaseAllowance(ctx, evm.Origin, stateDB, method, args)
// Staking transactions
case CreateValidatorMethod:
fedekunze marked this conversation as resolved.
Show resolved Hide resolved
bz, err = p.CreateValidator(ctx, evm.Origin, contract, stateDB, method, args)

Check warning on line 113 in precompiles/staking/staking.go

View check run for this annotation

Codecov / codecov/patch

precompiles/staking/staking.go#L112-L113

Added lines #L112 - L113 were not covered by tests
case DelegateMethod:
bz, err = p.Delegate(ctx, evm.Origin, contract, stateDB, method, args)
case UndelegateMethod:
Expand Down
48 changes: 48 additions & 0 deletions precompiles/staking/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
// CancelUnbondingDelegationMethod defines the ABI method name for the staking
// CancelUnbondingDelegation transaction.
CancelUnbondingDelegationMethod = "cancelUnbondingDelegation"
// CreateValidatorMethod defines the ABI method name for the staking create validator transaction
CreateValidatorMethod = "createValidator"
)

const (
Expand All @@ -43,6 +45,52 @@
CancelUnbondingDelegationAuthz = stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_CANCEL_UNBONDING_DELEGATION
)

// CreateValidator performs create validator.
func (p Precompile) CreateValidator(
ctx sdk.Context,
origin common.Address,
contract *vm.Contract,

Check warning on line 52 in precompiles/staking/tx.go

View workflow job for this annotation

GitHub Actions / Run golangci-lint

unused-parameter: parameter 'contract' seems to be unused, consider removing or renaming it as _ (revive)
fedekunze marked this conversation as resolved.
Show resolved Hide resolved
stateDB vm.StateDB,
method *abi.Method,
args []interface{},
) ([]byte, error) {
msg, delegatorHexAddr, err := NewMsgCreateValidator(args, p.stakingKeeper.BondDenom(ctx))
if err != nil {
return nil, err
}

Check warning on line 60 in precompiles/staking/tx.go

View check run for this annotation

Codecov / codecov/patch

precompiles/staking/tx.go#L56-L60

Added lines #L56 - L60 were not covered by tests

p.Logger(ctx).Debug(
"tx called",
"method", method.Name,
"args", fmt.Sprintf(
"{ min_self_delegation: %s, delegator_address: %s, validator_address: %s, pubkey: %s, value: %s }",
msg.MinSelfDelegation.String(),
delegatorHexAddr,
msg.ValidatorAddress,
msg.Pubkey.String(),
msg.Value.Amount.String(),
),
fedekunze marked this conversation as resolved.
Show resolved Hide resolved
)

// We only allow users to directly call the StakingI contract's address which is 0x0000000000000000000000000000000000000800 to create a new validator.
fedekunze marked this conversation as resolved.
Show resolved Hide resolved
if origin != delegatorHexAddr {
return nil, fmt.Errorf(ErrDifferentOriginFromDelegator, origin.String(), delegatorHexAddr.String())
}

Check warning on line 78 in precompiles/staking/tx.go

View check run for this annotation

Codecov / codecov/patch

precompiles/staking/tx.go#L62-L78

Added lines #L62 - L78 were not covered by tests

// Execute the transaction using the message server
msgSrv := stakingkeeper.NewMsgServerImpl(&p.stakingKeeper)
if _, err = msgSrv.CreateValidator(sdk.WrapSDKContext(ctx), msg); err != nil {
return nil, err
}

Check warning on line 84 in precompiles/staking/tx.go

View check run for this annotation

Codecov / codecov/patch

precompiles/staking/tx.go#L81-L84

Added lines #L81 - L84 were not covered by tests

// Emit the event for the delegate transaction
if err = p.EmitCreateValidatorEvent(ctx, stateDB, msg, delegatorHexAddr); err != nil {
return nil, err
}

Check warning on line 89 in precompiles/staking/tx.go

View check run for this annotation

Codecov / codecov/patch

precompiles/staking/tx.go#L87-L89

Added lines #L87 - L89 were not covered by tests

return method.Outputs.Pack(true)

Check warning on line 91 in precompiles/staking/tx.go

View check run for this annotation

Codecov / codecov/patch

precompiles/staking/tx.go#L91

Added line #L91 was not covered by tests
}

// Delegate performs a delegation of coins from a delegator to a validator.
func (p Precompile) Delegate(
ctx sdk.Context,
Expand Down