Skip to content

Commit

Permalink
[staking] add BucketTypes web3 api (#3876)
Browse files Browse the repository at this point in the history
  • Loading branch information
envestcc authored Jun 6, 2023
1 parent 2d573aa commit 59ad616
Show file tree
Hide file tree
Showing 3 changed files with 208 additions and 0 deletions.
27 changes: 27 additions & 0 deletions action/protocol/staking/ethabi/stake_base.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ type (
UnstakeStartBlockHeight uint64
}

// BucketTypeEth struct for eth
BucketTypeEth struct {
StakedAmount *big.Int
StakedDuration uint32
}

// CandidateEth struct for eth
CandidateEth struct {
OwnerAddress common.Address
Expand Down Expand Up @@ -133,6 +139,25 @@ func encodeCandidateToEth(candidate *iotextypes.CandidateV2) (*CandidateEth, err
return result, nil
}

func encodeBucketTypeListToEth(outputs abi.Arguments, bucketTypes iotextypes.ContractStakingBucketTypeList) (string, error) {
args := make([]BucketTypeEth, len(bucketTypes.BucketTypes))
for i, bt := range bucketTypes.BucketTypes {
args[i] = BucketTypeEth{}
if amount, ok := new(big.Int).SetString(bt.StakedAmount, 10); ok {
args[i].StakedAmount = amount
} else {
return "", errConvertBigNumber
}
args[i].StakedDuration = bt.StakedDuration
}

data, err := outputs.Pack(args)
if err != nil {
return "", err
}
return hex.EncodeToString(data), nil
}

// BuildReadStateRequest decode eth_call data to StateContext
func BuildReadStateRequest(data []byte) (protocol.StateContext, error) {
if len(data) < 4 {
Expand Down Expand Up @@ -170,6 +195,8 @@ func BuildReadStateRequest(data []byte) (protocol.StateContext, error) {
return newCompositeBucketsCountStateContext()
case hex.EncodeToString(_compositeTotalStakingAmountMethod.ID):
return newCompositeTotalStakingAmountContext()
case hex.EncodeToString(_contractBucketTypesMethod.ID):
return newContractBucketTypesStateContext(data[4:])
default:
return nil, errInvalidCallSig
}
Expand Down
112 changes: 112 additions & 0 deletions action/protocol/staking/ethabi/stake_contract_buckettypes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package ethabi

import (
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"google.golang.org/protobuf/proto"

"github.com/iotexproject/iotex-address/address"
"github.com/iotexproject/iotex-proto/golang/iotexapi"
"github.com/iotexproject/iotex-proto/golang/iotextypes"

"github.com/iotexproject/iotex-core/action/protocol"
"github.com/iotexproject/iotex-core/action/protocol/abiutil"
)

const _contractBucketTypesInterfaceABI = `[
{
"inputs": [
{
"internalType": "address",
"name": "contractAddress",
"type": "address"
}
],
"name": "contractStakeBucketTypes",
"outputs": [
{
"components": [
{
"internalType": "uint256",
"name": "stakedAmount",
"type": "uint256"
},
{
"internalType": "uint32",
"name": "stakedDuration",
"type": "uint32"
}
],
"internalType": "struct IStaking.BucketType[]",
"name": "",
"type": "tuple[]"
}
],
"stateMutability": "view",
"type": "function"
}
]`

var _contractBucketTypesMethod abi.Method

func init() {
_contractBucketTypesMethod = abiutil.MustLoadMethod(_contractBucketTypesInterfaceABI, "contractStakeBucketTypes")
}

// ContractBucketTypesStateContext context for Buckets
type ContractBucketTypesStateContext struct {
*protocol.BaseStateContext
}

func newContractBucketTypesStateContext(data []byte) (*ContractBucketTypesStateContext, error) {
paramsMap := map[string]interface{}{}
ok := false
if err := _contractBucketTypesMethod.Inputs.UnpackIntoMap(paramsMap, data); err != nil {
return nil, err
}
var contractAddr common.Address
if contractAddr, ok = paramsMap["contractAddress"].(common.Address); !ok {
return nil, errDecodeFailure
}
contractAddress, err := address.FromBytes(contractAddr[:])
if err != nil {
return nil, err
}

method := &iotexapi.ReadStakingDataMethod{
Method: iotexapi.ReadStakingDataMethod_CONTRACT_STAKING_BUCKET_TYPES,
}
methodBytes, err := proto.Marshal(method)
if err != nil {
return nil, err
}
arguments := &iotexapi.ReadStakingDataRequest{
Request: &iotexapi.ReadStakingDataRequest_ContractStakingBucketTypes_{
ContractStakingBucketTypes: &iotexapi.ReadStakingDataRequest_ContractStakingBucketTypes{
ContractAddress: contractAddress.String(),
},
},
}
argumentsBytes, err := proto.Marshal(arguments)
if err != nil {
return nil, err
}
return &ContractBucketTypesStateContext{
&protocol.BaseStateContext{
Parameter: &protocol.Parameters{
MethodName: methodBytes,
Arguments: [][]byte{argumentsBytes},
},
},
}, nil
}

// EncodeToEth encode proto to eth
func (r *ContractBucketTypesStateContext) EncodeToEth(resp *iotexapi.ReadStateResponse) (string, error) {
var result iotextypes.ContractStakingBucketTypeList
if err := proto.Unmarshal(resp.Data, &result); err != nil {
return "", err
}

return encodeBucketTypeListToEth(_contractBucketTypesMethod.Outputs, result)
}
69 changes: 69 additions & 0 deletions action/protocol/staking/ethabi/stake_contract_buckettypes_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package ethabi

import (
"encoding/hex"
"reflect"
"testing"

"github.com/ethereum/go-ethereum/common"
"github.com/iotexproject/iotex-address/address"
"github.com/iotexproject/iotex-proto/golang/iotexapi"
"github.com/iotexproject/iotex-proto/golang/iotextypes"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
)

func TestBuildReadStateRequestContractBucketTypes(t *testing.T) {
r := require.New(t)

addr, err := address.FromString("io1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqryn4k9fw")
r.NoError(err)
data, err := _contractBucketTypesMethod.Inputs.Pack(common.BytesToAddress(addr.Bytes()))
r.NoError(err)
data = append(_contractBucketTypesMethod.ID, data...)
t.Logf("data: %s", hex.EncodeToString(data))

data, err = hex.DecodeString("017619d40000000000000000000000000000000000000000000000000000000000000064")
r.NoError(err)
req, err := BuildReadStateRequest(data)
r.NoError(err)
r.EqualValues("*ethabi.ContractBucketTypesStateContext", reflect.TypeOf(req).String())

method := &iotexapi.ReadStakingDataMethod{
Method: iotexapi.ReadStakingDataMethod_CONTRACT_STAKING_BUCKET_TYPES,
}
methodBytes, _ := proto.Marshal(method)
r.EqualValues(methodBytes, req.Parameters().MethodName)

arguments := &iotexapi.ReadStakingDataRequest{
Request: &iotexapi.ReadStakingDataRequest_ContractStakingBucketTypes_{
ContractStakingBucketTypes: &iotexapi.ReadStakingDataRequest_ContractStakingBucketTypes{
ContractAddress: "io1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqryn4k9fw",
},
},
}
argumentsBytes, _ := proto.Marshal(arguments)
r.EqualValues([][]byte{argumentsBytes}, req.Parameters().Arguments)
}

func TestEncodeBucketTypeListToEth(t *testing.T) {
r := require.New(t)

bts := make([]*iotextypes.ContractStakingBucketType, 2)

bts[0] = &iotextypes.ContractStakingBucketType{
StakedAmount: "1000000000000000000",
StakedDuration: 1_000_000,
}
bts[1] = &iotextypes.ContractStakingBucketType{
StakedAmount: "2000000000000000000",
StakedDuration: 2_000_000,
}

data, err := encodeBucketTypeListToEth(_contractBucketTypesMethod.Outputs, iotextypes.ContractStakingBucketTypeList{
BucketTypes: bts,
})

r.Nil(err)
r.EqualValues("000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000f42400000000000000000000000000000000000000000000000001bc16d674ec8000000000000000000000000000000000000000000000000000000000000001e8480", data)
}

0 comments on commit 59ad616

Please sign in to comment.