Skip to content

Commit

Permalink
[api] web3 rewarding read api (#3693)
Browse files Browse the repository at this point in the history
* web3 rewarding read api

* refactor: Extract load abi method

* chore: Add method comment
  • Loading branch information
ququzone committed Nov 30, 2022
1 parent 14fd459 commit 663c991
Show file tree
Hide file tree
Showing 10 changed files with 433 additions and 0 deletions.
20 changes: 20 additions & 0 deletions action/protocol/abiutil/abiutil.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package abiutil

import (
"strings"

"github.com/ethereum/go-ethereum/accounts/abi"
)

// MustLoadMethod must load abi method
func MustLoadMethod(abiStr, method string) abi.Method {
_interface, err := abi.JSON(strings.NewReader(abiStr))
if err != nil {
panic(err)
}
_method, ok := _interface.Methods[method]
if !ok {
panic("fail to load the method")
}
return _method
}
65 changes: 65 additions & 0 deletions action/protocol/rewarding/ethabi/availablebalance.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package ethabi

import (
"encoding/hex"
"math/big"

"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/iotexproject/iotex-proto/golang/iotexapi"
"github.com/iotexproject/iotex-proto/golang/protocol"

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

const _availableBalanceInterfaceABI = `[
{
"inputs": [],
"name": "availableBalance",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
}
]`

var _availableBalanceMethod abi.Method

func init() {
_availableBalanceMethod = abiutil.MustLoadMethod(_availableBalanceInterfaceABI, "availableBalance")
}

// AvailableBalanceStateContext context for AvailableBalance
type AvailableBalanceStateContext struct {
*baseStateContext
}

func newAvailableBalanceStateContext() (*AvailableBalanceStateContext, error) {
return &AvailableBalanceStateContext{
&baseStateContext{
&Parameters{
MethodName: []byte(protocol.ReadAvailableBalanceMethodName),
Arguments: nil,
},
},
}, nil
}

// EncodeToEth encode proto to eth
func (r *AvailableBalanceStateContext) EncodeToEth(resp *iotexapi.ReadStateResponse) (string, error) {
total, ok := new(big.Int).SetString(string(resp.Data), 10)
if !ok {
return "", errConvertBigNumber
}

data, err := _availableBalanceMethod.Outputs.Pack(total)
if err != nil {
return "", nil
}

return hex.EncodeToString(data), nil
}
26 changes: 26 additions & 0 deletions action/protocol/rewarding/ethabi/availablebalance_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package ethabi

import (
"math/big"
"testing"

"github.com/iotexproject/iotex-proto/golang/iotexapi"
"github.com/stretchr/testify/require"
)

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

ctx, err := newAvailableBalanceStateContext()
r.Nil(err)
r.EqualValues("AvailableBalance", string(ctx.parameters.MethodName))

amount := big.NewInt(10000)
resp := &iotexapi.ReadStateResponse{
Data: []byte(amount.String()),
}

data, err := ctx.EncodeToEth(resp)
r.Nil(err)
r.EqualValues("0000000000000000000000000000000000000000000000000000000000002710", data)
}
55 changes: 55 additions & 0 deletions action/protocol/rewarding/ethabi/base.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package ethabi

import (
"encoding/hex"
"errors"

"github.com/iotexproject/iotex-proto/golang/iotexapi"
)

var (
errInvalidCallData = errors.New("invalid call binary data")
errInvalidCallSig = errors.New("invalid call sig")
errConvertBigNumber = errors.New("convert big number error")
errDecodeFailure = errors.New("decode data error")
)

type (
// Parameters state request parameters
Parameters struct {
MethodName []byte
Arguments [][]byte
}

// StateContext context for ReadState
StateContext interface {
Parameters() *Parameters
EncodeToEth(*iotexapi.ReadStateResponse) (string, error)
}

baseStateContext struct {
parameters *Parameters
}
)

func (r *baseStateContext) Parameters() *Parameters {
return r.parameters
}

// BuildReadStateRequest decode eth_call data to StateContext
func BuildReadStateRequest(data []byte) (StateContext, error) {
if len(data) < 4 {
return nil, errInvalidCallData
}

switch methodSig := hex.EncodeToString(data[:4]); methodSig {
case hex.EncodeToString(_totalBalanceMethod.ID):
return newTotalBalanceStateContext()
case hex.EncodeToString(_availableBalanceMethod.ID):
return newAvailableBalanceStateContext()
case hex.EncodeToString(_unclaimedBalanceMethod.ID):
return newUnclaimedBalanceStateContext(data[4:])
default:
return nil, errInvalidCallSig
}
}
37 changes: 37 additions & 0 deletions action/protocol/rewarding/ethabi/base_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package ethabi

import (
"encoding/hex"
"testing"

"github.com/stretchr/testify/require"
)

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

data, _ := hex.DecodeString("1234")
ctx, err := BuildReadStateRequest(data)
r.Nil(ctx)
r.EqualError(errInvalidCallData, err.Error())

data, _ = hex.DecodeString("12345678")
ctx, err = BuildReadStateRequest(data)
r.Nil(ctx)
r.EqualError(errInvalidCallSig, err.Error())

data, _ = hex.DecodeString("ad7a672f")
ctx, err = BuildReadStateRequest(data)
r.Nil(err)
r.IsType(&TotalBalanceStateContext{}, ctx)

data, _ = hex.DecodeString("ab2f0e51")
ctx, err = BuildReadStateRequest(data)
r.Nil(err)
r.IsType(&AvailableBalanceStateContext{}, ctx)

data, _ = hex.DecodeString("01cbf5fb0000000000000000000000000000000000000000000000000000000000000001")
ctx, err = BuildReadStateRequest(data)
r.Nil(err)
r.IsType(&UnclaimedBalanceStateContext{}, ctx)
}
65 changes: 65 additions & 0 deletions action/protocol/rewarding/ethabi/totalbalance.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package ethabi

import (
"encoding/hex"
"math/big"

"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/iotexproject/iotex-proto/golang/iotexapi"
"github.com/iotexproject/iotex-proto/golang/protocol"

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

const _totalBalanceInterfaceABI = `[
{
"inputs": [],
"name": "totalBalance",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
}
]`

var _totalBalanceMethod abi.Method

func init() {
_totalBalanceMethod = abiutil.MustLoadMethod(_totalBalanceInterfaceABI, "totalBalance")
}

// TotalBalanceStateContext context for TotalBalance
type TotalBalanceStateContext struct {
*baseStateContext
}

func newTotalBalanceStateContext() (*TotalBalanceStateContext, error) {
return &TotalBalanceStateContext{
&baseStateContext{
&Parameters{
MethodName: []byte(protocol.ReadTotalBalanceMethodName),
Arguments: nil,
},
},
}, nil
}

// EncodeToEth encode proto to eth
func (r *TotalBalanceStateContext) EncodeToEth(resp *iotexapi.ReadStateResponse) (string, error) {
total, ok := new(big.Int).SetString(string(resp.Data), 10)
if !ok {
return "", errConvertBigNumber
}

data, err := _totalBalanceMethod.Outputs.Pack(total)
if err != nil {
return "", nil
}

return hex.EncodeToString(data), nil
}
26 changes: 26 additions & 0 deletions action/protocol/rewarding/ethabi/totalbalance_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package ethabi

import (
"math/big"
"testing"

"github.com/iotexproject/iotex-proto/golang/iotexapi"
"github.com/stretchr/testify/require"
)

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

ctx, err := newTotalBalanceStateContext()
r.Nil(err)
r.EqualValues("TotalBalance", string(ctx.parameters.MethodName))

amount := big.NewInt(10000)
resp := &iotexapi.ReadStateResponse{
Data: []byte(amount.String()),
}

data, err := ctx.EncodeToEth(resp)
r.Nil(err)
r.EqualValues("0000000000000000000000000000000000000000000000000000000000002710", data)
}
87 changes: 87 additions & 0 deletions action/protocol/rewarding/ethabi/unclaimedbalance.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package ethabi

import (
"encoding/hex"
"math/big"

"github.com/ethereum/go-ethereum/accounts/abi"
"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/protocol"

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

const _unclaimedBalanceInterfaceABI = `[
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "unclaimedBalance",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
}
]`

var _unclaimedBalanceMethod abi.Method

func init() {
_unclaimedBalanceMethod = abiutil.MustLoadMethod(_unclaimedBalanceInterfaceABI, "unclaimedBalance")
}

// UnclaimedBalanceStateContext context for UnclaimedBalance
type UnclaimedBalanceStateContext struct {
*baseStateContext
}

func newUnclaimedBalanceStateContext(data []byte) (*UnclaimedBalanceStateContext, error) {
paramsMap := map[string]interface{}{}
ok := false
if err := _unclaimedBalanceMethod.Inputs.UnpackIntoMap(paramsMap, data); err != nil {
return nil, err
}
var account common.Address
if account, ok = paramsMap["account"].(common.Address); !ok {
return nil, errDecodeFailure
}
accountAddress, err := address.FromBytes(account[:])
if err != nil {
return nil, err
}

return &UnclaimedBalanceStateContext{
&baseStateContext{
&Parameters{
MethodName: []byte(protocol.ReadUnclaimedBalanceMethodName),
Arguments: [][]byte{[]byte(accountAddress.String())},
},
},
}, nil
}

// EncodeToEth encode proto to eth
func (r *UnclaimedBalanceStateContext) EncodeToEth(resp *iotexapi.ReadStateResponse) (string, error) {
total, ok := new(big.Int).SetString(string(resp.Data), 10)
if !ok {
return "", errConvertBigNumber
}

data, err := _unclaimedBalanceMethod.Outputs.Pack(total)
if err != nil {
return "", nil
}

return hex.EncodeToString(data), nil
}
Loading

0 comments on commit 663c991

Please sign in to comment.