fixed config + improved logging #132
@@ -34,16 +34,18 @@ messaging:
|
|||||||
reconnect_wait: 5
|
reconnect_wait: 5
|
||||||
|
|
||||||
chains:
|
chains:
|
||||||
- name: arbitrum_one
|
- name: tron
|
||||||
|
chain_id: 728126428
|
||||||
|
native_token: TRX
|
||||||
rpc_url_env: CHAIN_GATEWAY_RPC_URL
|
rpc_url_env: CHAIN_GATEWAY_RPC_URL
|
||||||
tokens:
|
tokens:
|
||||||
- symbol: USDC
|
|
||||||
contract: "0xaf88d065e77c8cc2239327c5edb3a432268e5831"
|
|
||||||
- symbol: USDT
|
- symbol: USDT
|
||||||
contract: "0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9"
|
contract: "0xa614f803b6fd780986a42c78ec9c7f77e6ded13c"
|
||||||
|
- symbol: USDC
|
||||||
|
contract: "0x3487b63d30b5b2c87fb7ffa8bcfade38eaac1abe"
|
||||||
|
|
||||||
service_wallet:
|
service_wallet:
|
||||||
chain: arbitrum_one
|
chain: tron
|
||||||
address_env: CHAIN_GATEWAY_SERVICE_WALLET_ADDRESS
|
address_env: CHAIN_GATEWAY_SERVICE_WALLET_ADDRESS
|
||||||
private_key_env: CHAIN_GATEWAY_SERVICE_WALLET_KEY
|
private_key_env: CHAIN_GATEWAY_SERVICE_WALLET_KEY
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package wallet
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -14,24 +15,53 @@ import (
|
|||||||
"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"
|
||||||
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
func onChainWalletBalance(ctx context.Context, deps Deps, wallet *model.ManagedWallet) (*moneyv1.Money, error) {
|
func onChainWalletBalance(ctx context.Context, deps Deps, wallet *model.ManagedWallet) (*moneyv1.Money, error) {
|
||||||
network := deps.Networks[strings.ToLower(strings.TrimSpace(wallet.Network))]
|
logger := deps.Logger
|
||||||
|
networkKey := strings.ToLower(strings.TrimSpace(wallet.Network))
|
||||||
|
network := deps.Networks[networkKey]
|
||||||
rpcURL := strings.TrimSpace(network.RPCURL)
|
rpcURL := strings.TrimSpace(network.RPCURL)
|
||||||
|
|
||||||
|
logFields := []zap.Field{
|
||||||
|
zap.String("wallet_ref", wallet.WalletRef),
|
||||||
|
zap.String("network", networkKey),
|
||||||
|
zap.String("token_symbol", strings.ToUpper(strings.TrimSpace(wallet.TokenSymbol))),
|
||||||
|
zap.String("contract", strings.ToLower(strings.TrimSpace(wallet.ContractAddress))),
|
||||||
|
zap.String("wallet_address", strings.ToLower(strings.TrimSpace(wallet.DepositAddress))),
|
||||||
|
zap.String("rpc_endpoint", safeRPCLabel(rpcURL)),
|
||||||
|
}
|
||||||
|
|
||||||
if rpcURL == "" {
|
if rpcURL == "" {
|
||||||
|
if logger != nil {
|
||||||
|
logger.Warn("network rpc url is not configured", logFields...)
|
||||||
|
}
|
||||||
return nil, merrors.Internal("network rpc url is not configured")
|
return nil, merrors.Internal("network rpc url is not configured")
|
||||||
}
|
}
|
||||||
contract := strings.TrimSpace(wallet.ContractAddress)
|
contract := strings.TrimSpace(wallet.ContractAddress)
|
||||||
if contract == "" || !common.IsHexAddress(contract) {
|
if contract == "" || !common.IsHexAddress(contract) {
|
||||||
|
if logger != nil {
|
||||||
|
logger.Warn("invalid contract address for balance fetch", logFields...)
|
||||||
|
}
|
||||||
return nil, merrors.InvalidArgument("invalid contract address")
|
return nil, merrors.InvalidArgument("invalid contract address")
|
||||||
}
|
}
|
||||||
if wallet.DepositAddress == "" || !common.IsHexAddress(wallet.DepositAddress) {
|
if wallet.DepositAddress == "" || !common.IsHexAddress(wallet.DepositAddress) {
|
||||||
|
if logger != nil {
|
||||||
|
logger.Warn("invalid wallet address for balance fetch", logFields...)
|
||||||
|
}
|
||||||
return nil, merrors.InvalidArgument("invalid wallet address")
|
return nil, merrors.InvalidArgument("invalid wallet address")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if logger != nil {
|
||||||
|
logger.Info("fetching on-chain wallet balance", logFields...)
|
||||||
|
}
|
||||||
|
|
||||||
client, err := ethclient.DialContext(ctx, rpcURL)
|
client, err := ethclient.DialContext(ctx, rpcURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if logger != nil {
|
||||||
|
logger.Warn("failed to connect rpc", append(logFields, zap.Error(err))...)
|
||||||
|
}
|
||||||
return nil, merrors.Internal("failed to connect rpc: " + err.Error())
|
return nil, merrors.Internal("failed to connect rpc: " + err.Error())
|
||||||
}
|
}
|
||||||
defer client.Close()
|
defer client.Close()
|
||||||
@@ -41,22 +71,46 @@ func onChainWalletBalance(ctx context.Context, deps Deps, wallet *model.ManagedW
|
|||||||
|
|
||||||
tokenABI, err := abi.JSON(strings.NewReader(erc20ABIJSON))
|
tokenABI, err := abi.JSON(strings.NewReader(erc20ABIJSON))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if logger != nil {
|
||||||
|
logger.Warn("failed to parse erc20 abi", append(logFields, zap.Error(err))...)
|
||||||
|
}
|
||||||
return nil, merrors.Internal("failed to parse erc20 abi: " + err.Error())
|
return nil, merrors.Internal("failed to parse erc20 abi: " + err.Error())
|
||||||
}
|
}
|
||||||
tokenAddr := common.HexToAddress(contract)
|
tokenAddr := common.HexToAddress(contract)
|
||||||
walletAddr := common.HexToAddress(wallet.DepositAddress)
|
walletAddr := common.HexToAddress(wallet.DepositAddress)
|
||||||
|
|
||||||
|
if logger != nil {
|
||||||
|
logger.Debug("calling token decimals", logFields...)
|
||||||
|
}
|
||||||
decimals, err := readDecimals(timeoutCtx, client, tokenABI, tokenAddr)
|
decimals, err := readDecimals(timeoutCtx, client, tokenABI, tokenAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if logger != nil {
|
||||||
|
logger.Warn("token decimals call failed", append(logFields, zap.Error(err))...)
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if logger != nil {
|
||||||
|
logger.Debug("calling token balanceOf", append(logFields, zap.Uint8("decimals", decimals))...)
|
||||||
|
}
|
||||||
bal, err := readBalanceOf(timeoutCtx, client, tokenABI, tokenAddr, walletAddr)
|
bal, err := readBalanceOf(timeoutCtx, client, tokenABI, tokenAddr, walletAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if logger != nil {
|
||||||
|
logger.Warn("token balanceOf call failed", append(logFields, zap.Uint8("decimals", decimals), zap.Error(err))...)
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
dec := decimal.NewFromBigInt(bal, 0).Shift(-int32(decimals))
|
dec := decimal.NewFromBigInt(bal, 0).Shift(-int32(decimals))
|
||||||
|
if logger != nil {
|
||||||
|
logger.Info("on-chain wallet balance fetched",
|
||||||
|
append(logFields,
|
||||||
|
zap.Uint8("decimals", decimals),
|
||||||
|
zap.String("balance_raw", bal.String()),
|
||||||
|
zap.String("balance", dec.String()),
|
||||||
|
)...,
|
||||||
|
)
|
||||||
|
}
|
||||||
return &moneyv1.Money{Currency: wallet.TokenSymbol, Amount: dec.String()}, nil
|
return &moneyv1.Money{Currency: wallet.TokenSymbol, Amount: dec.String()}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,3 +176,14 @@ const erc20ABIJSON = `
|
|||||||
"type": "function"
|
"type": "function"
|
||||||
}
|
}
|
||||||
]`
|
]`
|
||||||
|
|
||||||
|
func safeRPCLabel(raw string) string {
|
||||||
|
parsed, err := url.Parse(strings.TrimSpace(raw))
|
||||||
|
if err != nil || parsed.Host == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
parsed.User = nil
|
||||||
|
parsed.RawQuery = ""
|
||||||
|
parsed.Fragment = ""
|
||||||
|
return parsed.String()
|
||||||
|
}
|
||||||
|
|||||||
@@ -48,28 +48,28 @@ type onChainExecutor struct {
|
|||||||
|
|
||||||
func (o *onChainExecutor) SubmitTransfer(ctx context.Context, transfer *model.Transfer, source *model.ManagedWallet, destinationAddress string, network shared.Network) (string, error) {
|
func (o *onChainExecutor) SubmitTransfer(ctx context.Context, transfer *model.Transfer, source *model.ManagedWallet, destinationAddress string, network shared.Network) (string, error) {
|
||||||
if o.keyManager == nil {
|
if o.keyManager == nil {
|
||||||
o.logger.Error("key manager not configured")
|
o.logger.Warn("key manager not configured")
|
||||||
return "", executorInternal("key manager is not configured", nil)
|
return "", executorInternal("key manager is not configured", nil)
|
||||||
}
|
}
|
||||||
rpcURL := strings.TrimSpace(network.RPCURL)
|
rpcURL := strings.TrimSpace(network.RPCURL)
|
||||||
if rpcURL == "" {
|
if rpcURL == "" {
|
||||||
o.logger.Error("network rpc url missing", zap.String("network", network.Name))
|
o.logger.Warn("network rpc url missing", zap.String("network", network.Name))
|
||||||
return "", executorInvalid("network rpc url is not configured")
|
return "", executorInvalid("network rpc url is not configured")
|
||||||
}
|
}
|
||||||
if source == nil || transfer == nil {
|
if source == nil || transfer == nil {
|
||||||
o.logger.Error("transfer context missing")
|
o.logger.Warn("transfer context missing")
|
||||||
return "", executorInvalid("transfer context missing")
|
return "", executorInvalid("transfer context missing")
|
||||||
}
|
}
|
||||||
if strings.TrimSpace(source.KeyReference) == "" {
|
if strings.TrimSpace(source.KeyReference) == "" {
|
||||||
o.logger.Error("source wallet missing key reference", zap.String("wallet_ref", source.WalletRef))
|
o.logger.Warn("source wallet missing key reference", zap.String("wallet_ref", source.WalletRef))
|
||||||
return "", executorInvalid("source wallet missing key reference")
|
return "", executorInvalid("source wallet missing key reference")
|
||||||
}
|
}
|
||||||
if strings.TrimSpace(source.DepositAddress) == "" {
|
if strings.TrimSpace(source.DepositAddress) == "" {
|
||||||
o.logger.Error("source wallet missing deposit address", zap.String("wallet_ref", source.WalletRef))
|
o.logger.Warn("source wallet missing deposit address", zap.String("wallet_ref", source.WalletRef))
|
||||||
return "", executorInvalid("source wallet missing deposit address")
|
return "", executorInvalid("source wallet missing deposit address")
|
||||||
}
|
}
|
||||||
if !common.IsHexAddress(destinationAddress) {
|
if !common.IsHexAddress(destinationAddress) {
|
||||||
o.logger.Error("invalid destination address", zap.String("transfer_ref", transfer.TransferRef), zap.String("address", destinationAddress))
|
o.logger.Warn("invalid destination address", zap.String("transfer_ref", transfer.TransferRef), zap.String("address", destinationAddress))
|
||||||
return "", executorInvalid("invalid destination address " + destinationAddress)
|
return "", executorInvalid("invalid destination address " + destinationAddress)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ func (s *Service) launchTransferExecution(transferRef, sourceWalletRef string, n
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := s.executeTransfer(ctx, ref, walletRef, net); err != nil {
|
if err := s.executeTransfer(ctx, ref, walletRef, net); err != nil {
|
||||||
s.logger.Error("failed to execute transfer", zap.String("transfer_ref", ref), zap.Error(err))
|
s.logger.Warn("failed to execute transfer", zap.String("transfer_ref", ref), zap.Error(err))
|
||||||
}
|
}
|
||||||
}(transferRef, sourceWalletRef, network)
|
}(transferRef, sourceWalletRef, network)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user