hex parser + test #141
@@ -10,7 +10,6 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum"
|
"github.com/ethereum/go-ethereum"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
"github.com/shopspring/decimal"
|
"github.com/shopspring/decimal"
|
||||||
"github.com/tech/sendico/gateway/chain/internal/service/gateway/rpcclient"
|
"github.com/tech/sendico/gateway/chain/internal/service/gateway/rpcclient"
|
||||||
@@ -199,17 +198,11 @@ func erc20Decimals(ctx context.Context, client *rpc.Client, token common.Address
|
|||||||
if err := client.CallContext(ctx, &hexResp, "eth_call", call, "latest"); err != nil {
|
if err := client.CallContext(ctx, &hexResp, "eth_call", call, "latest"); err != nil {
|
||||||
return 0, merrors.Internal("decimals call failed: " + err.Error())
|
return 0, merrors.Internal("decimals call failed: " + err.Error())
|
||||||
}
|
}
|
||||||
val, err := hexutil.DecodeBig(hexResp)
|
val, err := shared.DecodeHexUint8(hexResp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, merrors.Internal("decimals decode failed: " + err.Error())
|
return 0, merrors.Internal("decimals decode failed: " + err.Error())
|
||||||
}
|
}
|
||||||
if val == nil {
|
return val, nil
|
||||||
return 0, merrors.Internal("decimals decode failed: empty response")
|
|
||||||
}
|
|
||||||
if val.BitLen() > 8 {
|
|
||||||
return 0, merrors.Internal("decimals decode failed: value out of range")
|
|
||||||
}
|
|
||||||
return uint8(val.Uint64()), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func toBaseUnits(amount string, decimals uint8) (*big.Int, error) {
|
func toBaseUnits(amount string, decimals uint8) (*big.Int, error) {
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
"github.com/shopspring/decimal"
|
"github.com/shopspring/decimal"
|
||||||
|
"github.com/tech/sendico/gateway/chain/internal/service/gateway/shared"
|
||||||
"github.com/tech/sendico/gateway/chain/storage/model"
|
"github.com/tech/sendico/gateway/chain/storage/model"
|
||||||
"github.com/tech/sendico/pkg/merrors"
|
"github.com/tech/sendico/pkg/merrors"
|
||||||
moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
|
moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
|
||||||
@@ -104,17 +104,11 @@ func readDecimals(ctx context.Context, client *rpc.Client, token string) (uint8,
|
|||||||
if err := client.CallContext(ctx, &hexResp, "eth_call", call, "latest"); err != nil {
|
if err := client.CallContext(ctx, &hexResp, "eth_call", call, "latest"); err != nil {
|
||||||
return 0, merrors.Internal("decimals call failed: " + err.Error())
|
return 0, merrors.Internal("decimals call failed: " + err.Error())
|
||||||
}
|
}
|
||||||
val, err := hexutil.DecodeBig(hexResp)
|
val, err := shared.DecodeHexUint8(hexResp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, merrors.Internal("decimals decode failed: " + err.Error())
|
return 0, merrors.Internal("decimals decode failed: " + err.Error())
|
||||||
}
|
}
|
||||||
if val == nil {
|
return val, nil
|
||||||
return 0, merrors.Internal("decimals decode failed: empty response")
|
|
||||||
}
|
|
||||||
if val.BitLen() > 8 {
|
|
||||||
return 0, merrors.Internal("decimals decode failed: value out of range")
|
|
||||||
}
|
|
||||||
return uint8(val.Uint64()), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func readBalanceOf(ctx context.Context, client *rpc.Client, token string, wallet string) (*big.Int, error) {
|
func readBalanceOf(ctx context.Context, client *rpc.Client, token string, wallet string) (*big.Int, error) {
|
||||||
@@ -132,7 +126,7 @@ func readBalanceOf(ctx context.Context, client *rpc.Client, token string, wallet
|
|||||||
if err := client.CallContext(ctx, &hexResp, "eth_call", call, "latest"); err != nil {
|
if err := client.CallContext(ctx, &hexResp, "eth_call", call, "latest"); err != nil {
|
||||||
return nil, merrors.Internal("balanceOf call failed: " + err.Error())
|
return nil, merrors.Internal("balanceOf call failed: " + err.Error())
|
||||||
}
|
}
|
||||||
bigVal, err := hexutil.DecodeBig(hexResp)
|
bigVal, err := shared.DecodeHexBig(hexResp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, merrors.Internal("balanceOf decode failed: " + err.Error())
|
return nil, merrors.Internal("balanceOf decode failed: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum"
|
"github.com/ethereum/go-ethereum"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
"github.com/shopspring/decimal"
|
"github.com/shopspring/decimal"
|
||||||
@@ -315,17 +314,11 @@ func erc20Decimals(ctx context.Context, client *rpc.Client, token common.Address
|
|||||||
if err := client.CallContext(ctx, &hexResp, "eth_call", call, "latest"); err != nil {
|
if err := client.CallContext(ctx, &hexResp, "eth_call", call, "latest"); err != nil {
|
||||||
return 0, executorInternal("decimals call failed", err)
|
return 0, executorInternal("decimals call failed", err)
|
||||||
}
|
}
|
||||||
val, err := hexutil.DecodeBig(hexResp)
|
val, err := shared.DecodeHexUint8(hexResp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, executorInternal("decimals decode failed", err)
|
return 0, executorInternal("decimals decode failed", err)
|
||||||
}
|
}
|
||||||
if val == nil {
|
return val, nil
|
||||||
return 0, executorInternal("decimals decode failed", errors.New("empty response"))
|
|
||||||
}
|
|
||||||
if val.BitLen() > 8 {
|
|
||||||
return 0, executorInternal("decimals decode failed", errors.New("value out of range"))
|
|
||||||
}
|
|
||||||
return uint8(val.Uint64()), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func toBaseUnits(amount string, decimals uint8) (*big.Int, error) {
|
func toBaseUnits(amount string, decimals uint8) (*big.Int, error) {
|
||||||
|
|||||||
49
api/gateway/chain/internal/service/gateway/shared/hex.go
Normal file
49
api/gateway/chain/internal/service/gateway/shared/hex.go
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
package shared
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"math/big"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errHexEmpty = errors.New("hex value is empty")
|
||||||
|
errHexInvalid = errors.New("invalid hex number")
|
||||||
|
errHexOutOfRange = errors.New("hex number out of range")
|
||||||
|
)
|
||||||
|
|
||||||
|
// DecodeHexBig parses a hex string that may include leading zero digits.
|
||||||
|
func DecodeHexBig(input string) (*big.Int, error) {
|
||||||
|
trimmed := strings.TrimSpace(input)
|
||||||
|
if trimmed == "" {
|
||||||
|
return nil, errHexEmpty
|
||||||
|
}
|
||||||
|
noPrefix := strings.TrimPrefix(trimmed, "0x")
|
||||||
|
if noPrefix == "" {
|
||||||
|
return nil, errHexEmpty
|
||||||
|
}
|
||||||
|
value := strings.TrimLeft(noPrefix, "0")
|
||||||
|
if value == "" {
|
||||||
|
return big.NewInt(0), nil
|
||||||
|
}
|
||||||
|
val := new(big.Int)
|
||||||
|
if _, ok := val.SetString(value, 16); !ok {
|
||||||
|
return nil, errHexInvalid
|
||||||
|
}
|
||||||
|
return val, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeHexUint8 parses a hex string into uint8, allowing leading zeros.
|
||||||
|
func DecodeHexUint8(input string) (uint8, error) {
|
||||||
|
val, err := DecodeHexBig(input)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if val == nil {
|
||||||
|
return 0, errHexInvalid
|
||||||
|
}
|
||||||
|
if val.BitLen() > 8 {
|
||||||
|
return 0, errHexOutOfRange
|
||||||
|
}
|
||||||
|
return uint8(val.Uint64()), nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package shared
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestDecodeHexUint8_LeadingZeros(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
const resp = "0x0000000000000000000000000000000000000000000000000000000000000006"
|
||||||
|
val, err := DecodeHexUint8(resp)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("DecodeHexUint8 error: %v", err)
|
||||||
|
}
|
||||||
|
if val != 6 {
|
||||||
|
t.Fatalf("DecodeHexUint8 value = %d, want 6", val)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user