fixed proto message
This commit is contained in:
@@ -10,8 +10,10 @@ import (
|
||||
"github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/shopspring/decimal"
|
||||
"github.com/tech/sendico/gateway/chain/internal/service/gateway/rpcclient"
|
||||
"github.com/tech/sendico/gateway/chain/internal/service/gateway/shared"
|
||||
"github.com/tech/sendico/gateway/chain/storage/model"
|
||||
"github.com/tech/sendico/pkg/api/routers/gsresponse"
|
||||
@@ -85,7 +87,7 @@ func (c *estimateTransferFeeCommand) Execute(ctx context.Context, req *chainv1.E
|
||||
return gsresponse.InvalidArgument[chainv1.EstimateTransferFeeResponse](c.deps.Logger, mservice.ChainGateway, err)
|
||||
}
|
||||
|
||||
feeMoney, err := estimateNetworkFee(ctx, c.deps.Logger, networkCfg, c.deps.RPCTimeout, sourceWallet, destinationAddress, amount)
|
||||
feeMoney, err := estimateNetworkFee(ctx, c.deps.Logger, c.deps.Networks, networkCfg, c.deps.RPCTimeout, sourceWallet, destinationAddress, amount)
|
||||
if err != nil {
|
||||
c.deps.Logger.Warn("fee estimation failed", zap.Error(err))
|
||||
return gsresponse.Auto[chainv1.EstimateTransferFeeResponse](c.deps.Logger, mservice.ChainGateway, err)
|
||||
@@ -98,11 +100,14 @@ func (c *estimateTransferFeeCommand) Execute(ctx context.Context, req *chainv1.E
|
||||
return gsresponse.Success(resp)
|
||||
}
|
||||
|
||||
func estimateNetworkFee(ctx context.Context, logger mlogger.Logger, network shared.Network, timeout time.Duration, wallet *model.ManagedWallet, destination string, amount *moneyv1.Money) (*moneyv1.Money, error) {
|
||||
func estimateNetworkFee(ctx context.Context, logger mlogger.Logger, registry *rpcclient.Registry, network shared.Network, timeout time.Duration, wallet *model.ManagedWallet, destination string, amount *moneyv1.Money) (*moneyv1.Money, error) {
|
||||
rpcURL := strings.TrimSpace(network.RPCURL)
|
||||
if rpcURL == "" {
|
||||
return nil, merrors.InvalidArgument("network rpc url not configured")
|
||||
}
|
||||
if registry == nil {
|
||||
return nil, merrors.Internal("rpc clients not initialised")
|
||||
}
|
||||
if strings.TrimSpace(wallet.ContractAddress) == "" {
|
||||
return nil, merrors.NotImplemented("native token transfers not supported")
|
||||
}
|
||||
@@ -116,11 +121,14 @@ func estimateNetworkFee(ctx context.Context, logger mlogger.Logger, network shar
|
||||
return nil, merrors.InvalidArgument("invalid destination address")
|
||||
}
|
||||
|
||||
client, err := ethclient.DialContext(ctx, rpcURL)
|
||||
client, err := registry.Client(network.Name)
|
||||
if err != nil {
|
||||
return nil, merrors.Internal("failed to connect to rpc: " + err.Error())
|
||||
return nil, err
|
||||
}
|
||||
rpcClient, err := registry.RPCClient(network.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
if timeout <= 0 {
|
||||
timeout = 15 * time.Second
|
||||
@@ -136,7 +144,7 @@ func estimateNetworkFee(ctx context.Context, logger mlogger.Logger, network shar
|
||||
toAddr := common.HexToAddress(destination)
|
||||
fromAddr := common.HexToAddress(wallet.DepositAddress)
|
||||
|
||||
decimals, err := erc20Decimals(timeoutCtx, client, tokenABI, tokenAddr)
|
||||
decimals, err := erc20Decimals(timeoutCtx, rpcClient, tokenAddr)
|
||||
if err != nil {
|
||||
logger.Warn("failed to read token decimals", zap.Error(err))
|
||||
return nil, err
|
||||
@@ -182,31 +190,20 @@ func estimateNetworkFee(ctx context.Context, logger mlogger.Logger, network shar
|
||||
}, nil
|
||||
}
|
||||
|
||||
func erc20Decimals(ctx context.Context, client *ethclient.Client, tokenABI abi.ABI, token common.Address) (uint8, error) {
|
||||
callData, err := tokenABI.Pack("decimals")
|
||||
if err != nil {
|
||||
return 0, merrors.Internal("failed to encode decimals call: " + err.Error())
|
||||
func erc20Decimals(ctx context.Context, client *rpc.Client, token common.Address) (uint8, error) {
|
||||
call := map[string]string{
|
||||
"to": strings.ToLower(token.Hex()),
|
||||
"data": "0x313ce567",
|
||||
}
|
||||
msg := ethereum.CallMsg{
|
||||
To: &token,
|
||||
Data: callData,
|
||||
}
|
||||
output, err := client.CallContract(ctx, msg, nil)
|
||||
if err != nil {
|
||||
var hexResp string
|
||||
if err := client.CallContext(ctx, &hexResp, "eth_call", call, "latest"); err != nil {
|
||||
return 0, merrors.Internal("decimals call failed: " + err.Error())
|
||||
}
|
||||
values, err := tokenABI.Unpack("decimals", output)
|
||||
val, err := hexutil.DecodeUint64(hexResp)
|
||||
if err != nil {
|
||||
return 0, merrors.Internal("failed to unpack decimals: " + err.Error())
|
||||
return 0, merrors.Internal("decimals decode failed: " + err.Error())
|
||||
}
|
||||
if len(values) == 0 {
|
||||
return 0, merrors.Internal("decimals call returned no data")
|
||||
}
|
||||
decimals, ok := values[0].(uint8)
|
||||
if !ok {
|
||||
return 0, merrors.Internal("decimals call returned unexpected type")
|
||||
}
|
||||
return decimals, nil
|
||||
return uint8(val), nil
|
||||
}
|
||||
|
||||
func toBaseUnits(amount string, decimals uint8) (*big.Int, error) {
|
||||
|
||||
@@ -7,10 +7,9 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/shopspring/decimal"
|
||||
"github.com/tech/sendico/gateway/chain/storage/model"
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
@@ -58,7 +57,7 @@ func onChainWalletBalance(ctx context.Context, deps Deps, wallet *model.ManagedW
|
||||
|
||||
logger.Info("Fetching on-chain wallet balance", logFields...)
|
||||
|
||||
client, err := registry.Client(networkKey)
|
||||
rpcClient, err := registry.RPCClient(networkKey)
|
||||
if err != nil {
|
||||
logger.Warn("Failed to fetch rpc client", append(logFields, zap.Error(err))...)
|
||||
return nil, err
|
||||
@@ -71,23 +70,15 @@ func onChainWalletBalance(ctx context.Context, deps Deps, wallet *model.ManagedW
|
||||
timeoutCtx, cancel := context.WithTimeout(ctx, timeout)
|
||||
defer cancel()
|
||||
|
||||
tokenABI, err := abi.JSON(strings.NewReader(erc20ABIJSON))
|
||||
if err != nil {
|
||||
logger.Warn("Failed to parse erc20 abi", append(logFields, zap.Error(err))...)
|
||||
return nil, merrors.Internal("failed to parse erc20 abi: " + err.Error())
|
||||
}
|
||||
tokenAddr := common.HexToAddress(contract)
|
||||
walletAddr := common.HexToAddress(wallet.DepositAddress)
|
||||
|
||||
logger.Debug("Calling token decimals", logFields...)
|
||||
decimals, err := readDecimals(timeoutCtx, client, tokenABI, tokenAddr)
|
||||
decimals, err := readDecimals(timeoutCtx, rpcClient, contract)
|
||||
if err != nil {
|
||||
logger.Warn("Token decimals call failed", append(logFields, zap.Error(err))...)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
logger.Debug("Calling token balanceOf", append(logFields, zap.Uint8("decimals", decimals))...)
|
||||
bal, err := readBalanceOf(timeoutCtx, client, tokenABI, tokenAddr, walletAddr)
|
||||
bal, err := readBalanceOf(timeoutCtx, rpcClient, contract, wallet.DepositAddress)
|
||||
if err != nil {
|
||||
logger.Warn("Token balanceOf call failed", append(logFields, zap.Uint8("decimals", decimals), zap.Error(err))...)
|
||||
return nil, err
|
||||
@@ -104,65 +95,40 @@ func onChainWalletBalance(ctx context.Context, deps Deps, wallet *model.ManagedW
|
||||
return &moneyv1.Money{Currency: wallet.TokenSymbol, Amount: dec.String()}, nil
|
||||
}
|
||||
|
||||
func readDecimals(ctx context.Context, client *ethclient.Client, tokenABI abi.ABI, token common.Address) (uint8, error) {
|
||||
data, err := tokenABI.Pack("decimals")
|
||||
if err != nil {
|
||||
return 0, merrors.Internal("failed to encode decimals call: " + err.Error())
|
||||
func readDecimals(ctx context.Context, client *rpc.Client, token string) (uint8, error) {
|
||||
call := map[string]string{
|
||||
"to": strings.ToLower(common.HexToAddress(token).Hex()),
|
||||
"data": "0x313ce567",
|
||||
}
|
||||
msg := ethereum.CallMsg{To: &token, Data: data}
|
||||
out, err := client.CallContract(ctx, msg, nil)
|
||||
if err != nil {
|
||||
var hexResp string
|
||||
if err := client.CallContext(ctx, &hexResp, "eth_call", call, "latest"); err != nil {
|
||||
return 0, merrors.Internal("decimals call failed: " + err.Error())
|
||||
}
|
||||
values, err := tokenABI.Unpack("decimals", out)
|
||||
if err != nil || len(values) == 0 {
|
||||
return 0, merrors.Internal("failed to unpack decimals")
|
||||
val, err := hexutil.DecodeUint64(hexResp)
|
||||
if err != nil {
|
||||
return 0, merrors.Internal("decimals decode failed: " + err.Error())
|
||||
}
|
||||
if val, ok := values[0].(uint8); ok {
|
||||
return val, nil
|
||||
}
|
||||
return 0, merrors.Internal("decimals returned unexpected type")
|
||||
return uint8(val), nil
|
||||
}
|
||||
|
||||
func readBalanceOf(ctx context.Context, client *ethclient.Client, tokenABI abi.ABI, token common.Address, wallet common.Address) (*big.Int, error) {
|
||||
data, err := tokenABI.Pack("balanceOf", wallet)
|
||||
if err != nil {
|
||||
return nil, merrors.Internal("failed to encode balanceOf: " + err.Error())
|
||||
func readBalanceOf(ctx context.Context, client *rpc.Client, token string, wallet string) (*big.Int, error) {
|
||||
tokenAddr := common.HexToAddress(token)
|
||||
walletAddr := common.HexToAddress(wallet)
|
||||
addr := strings.TrimPrefix(walletAddr.Hex(), "0x")
|
||||
if len(addr) < 64 {
|
||||
addr = strings.Repeat("0", 64-len(addr)) + addr
|
||||
}
|
||||
msg := ethereum.CallMsg{To: &token, Data: data}
|
||||
out, err := client.CallContract(ctx, msg, nil)
|
||||
if err != nil {
|
||||
call := map[string]string{
|
||||
"to": strings.ToLower(tokenAddr.Hex()),
|
||||
"data": "0x70a08231" + addr,
|
||||
}
|
||||
var hexResp string
|
||||
if err := client.CallContext(ctx, &hexResp, "eth_call", call, "latest"); err != nil {
|
||||
return nil, merrors.Internal("balanceOf call failed: " + err.Error())
|
||||
}
|
||||
values, err := tokenABI.Unpack("balanceOf", out)
|
||||
if err != nil || len(values) == 0 {
|
||||
return nil, merrors.Internal("failed to unpack balanceOf")
|
||||
bigVal, err := hexutil.DecodeBig(hexResp)
|
||||
if err != nil {
|
||||
return nil, merrors.Internal("balanceOf decode failed: " + err.Error())
|
||||
}
|
||||
raw, ok := values[0].(*big.Int)
|
||||
if !ok {
|
||||
return nil, merrors.Internal("balanceOf returned unexpected type")
|
||||
}
|
||||
return decimal.NewFromBigInt(raw, 0).BigInt(), nil
|
||||
return bigVal, nil
|
||||
}
|
||||
|
||||
const erc20ABIJSON = `
|
||||
[
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "decimals",
|
||||
"outputs": [{ "name": "", "type": "uint8" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [{ "name": "_owner", "type": "address" }],
|
||||
"name": "balanceOf",
|
||||
"outputs": [{ "name": "balance", "type": "uint256" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
}
|
||||
]`
|
||||
|
||||
Reference in New Issue
Block a user