Added new tron networks
This commit is contained in:
@@ -34,8 +34,8 @@ messaging:
|
|||||||
reconnect_wait: 5
|
reconnect_wait: 5
|
||||||
|
|
||||||
chains:
|
chains:
|
||||||
- name: tron
|
- name: tron_mainnet
|
||||||
chain_id: 728126428
|
chain_id: 728126428 # 0x2b6653dc
|
||||||
native_token: TRX
|
native_token: TRX
|
||||||
rpc_url_env: CHAIN_GATEWAY_RPC_URL
|
rpc_url_env: CHAIN_GATEWAY_RPC_URL
|
||||||
tokens:
|
tokens:
|
||||||
@@ -45,7 +45,7 @@ chains:
|
|||||||
contract: "0x3487b63d30b5b2c87fb7ffa8bcfade38eaac1abe"
|
contract: "0x3487b63d30b5b2c87fb7ffa8bcfade38eaac1abe"
|
||||||
|
|
||||||
service_wallet:
|
service_wallet:
|
||||||
chain: tron
|
chain: tron_mainnet
|
||||||
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
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package serverimp
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -98,7 +99,11 @@ func (i *Imp) Start() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cl := i.logger.Named("config")
|
cl := i.logger.Named("config")
|
||||||
networkConfigs := resolveNetworkConfigs(cl.Named("network"), cfg.Chains)
|
networkConfigs, err := resolveNetworkConfigs(cl.Named("network"), cfg.Chains)
|
||||||
|
if err != nil {
|
||||||
|
i.logger.Error("invalid chain network configuration", zap.Error(err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
walletConfig := resolveServiceWallet(cl.Named("wallet"), cfg.ServiceWallet)
|
walletConfig := resolveServiceWallet(cl.Named("wallet"), cfg.ServiceWallet)
|
||||||
keyManager, err := resolveKeyManager(i.logger.Named("key_manager"), cfg.KeyManagement)
|
keyManager, err := resolveKeyManager(i.logger.Named("key_manager"), cfg.KeyManagement)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -157,7 +162,7 @@ func (i *Imp) loadConfig() (*config, error) {
|
|||||||
return cfg, nil
|
return cfg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func resolveNetworkConfigs(logger mlogger.Logger, chains []chainConfig) []gatewayshared.Network {
|
func resolveNetworkConfigs(logger mlogger.Logger, chains []chainConfig) ([]gatewayshared.Network, error) {
|
||||||
result := make([]gatewayshared.Network, 0, len(chains))
|
result := make([]gatewayshared.Network, 0, len(chains))
|
||||||
for _, chain := range chains {
|
for _, chain := range chains {
|
||||||
if strings.TrimSpace(chain.Name) == "" {
|
if strings.TrimSpace(chain.Name) == "" {
|
||||||
@@ -166,7 +171,8 @@ func resolveNetworkConfigs(logger mlogger.Logger, chains []chainConfig) []gatewa
|
|||||||
}
|
}
|
||||||
rpcURL := strings.TrimSpace(os.Getenv(chain.RPCURLEnv))
|
rpcURL := strings.TrimSpace(os.Getenv(chain.RPCURLEnv))
|
||||||
if rpcURL == "" {
|
if rpcURL == "" {
|
||||||
logger.Warn("chain RPC endpoint not configured", zap.String("chain", chain.Name), zap.String("env", chain.RPCURLEnv))
|
logger.Error("RPC url not configured", zap.String("chain", chain.Name), zap.String("env", chain.RPCURLEnv))
|
||||||
|
return nil, merrors.InvalidArgument(fmt.Sprintf("chain RPC endpoint not configured (chain=%s env=%s)", chain.Name, chain.RPCURLEnv))
|
||||||
}
|
}
|
||||||
contracts := make([]gatewayshared.TokenContract, 0, len(chain.Tokens))
|
contracts := make([]gatewayshared.TokenContract, 0, len(chain.Tokens))
|
||||||
for _, token := range chain.Tokens {
|
for _, token := range chain.Tokens {
|
||||||
@@ -202,7 +208,7 @@ func resolveNetworkConfigs(logger mlogger.Logger, chains []chainConfig) []gatewa
|
|||||||
TokenConfigs: contracts,
|
TokenConfigs: contracts,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return result
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func resolveServiceWallet(logger mlogger.Logger, cfg serviceWalletConfig) gatewayshared.ServiceWallet {
|
func resolveServiceWallet(logger mlogger.Logger, cfg serviceWalletConfig) gatewayshared.ServiceWallet {
|
||||||
|
|||||||
@@ -22,8 +22,9 @@ type Deps struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d Deps) WithLogger(name string) Deps {
|
func (d Deps) WithLogger(name string) Deps {
|
||||||
if d.Logger != nil {
|
if d.Logger == nil {
|
||||||
d.Logger = d.Logger.Named(name)
|
panic("wallet deps: logger is required")
|
||||||
}
|
}
|
||||||
|
d.Logger = d.Logger.Named(name)
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,34 +34,24 @@ func onChainWalletBalance(ctx context.Context, deps Deps, wallet *model.ManagedW
|
|||||||
}
|
}
|
||||||
|
|
||||||
if rpcURL == "" {
|
if rpcURL == "" {
|
||||||
if logger != nil {
|
logger.Warn("network rpc url is not configured", logFields...)
|
||||||
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...)
|
||||||
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...)
|
||||||
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...)
|
||||||
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))...)
|
||||||
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()
|
||||||
@@ -71,46 +61,34 @@ 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))...)
|
||||||
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...)
|
||||||
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))...)
|
||||||
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))...)
|
||||||
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))...)
|
||||||
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",
|
||||||
logger.Info("on-chain wallet balance fetched",
|
append(logFields,
|
||||||
append(logFields,
|
zap.Uint8("decimals", decimals),
|
||||||
zap.Uint8("decimals", decimals),
|
zap.String("balance_raw", bal.String()),
|
||||||
zap.String("balance_raw", bal.String()),
|
zap.String("balance", dec.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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ enum ChainNetwork {
|
|||||||
CHAIN_NETWORK_ETHEREUM_MAINNET = 1;
|
CHAIN_NETWORK_ETHEREUM_MAINNET = 1;
|
||||||
CHAIN_NETWORK_ARBITRUM_ONE = 2;
|
CHAIN_NETWORK_ARBITRUM_ONE = 2;
|
||||||
CHAIN_NETWORK_OTHER_EVM = 3;
|
CHAIN_NETWORK_OTHER_EVM = 3;
|
||||||
|
CHAIN_NETWORK_TRON_MAINNET = 4;
|
||||||
|
CHAIN_NETWORK_TRON_NILE = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ManagedWalletStatus {
|
enum ManagedWalletStatus {
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ api:
|
|||||||
call_timeout_seconds: 5
|
call_timeout_seconds: 5
|
||||||
insecure: true
|
insecure: true
|
||||||
default_asset:
|
default_asset:
|
||||||
chain: ARBITRUM_ONE
|
chain: TRON_MAINNET
|
||||||
token_symbol: USDT
|
token_symbol: USDT
|
||||||
contract_address: ""
|
contract_address: ""
|
||||||
ledger:
|
ledger:
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ const (
|
|||||||
ChainNetworkEthereumMainnet ChainNetwork = "ethereum_mainnet"
|
ChainNetworkEthereumMainnet ChainNetwork = "ethereum_mainnet"
|
||||||
ChainNetworkArbitrumOne ChainNetwork = "arbitrum_one"
|
ChainNetworkArbitrumOne ChainNetwork = "arbitrum_one"
|
||||||
ChainNetworkOtherEVM ChainNetwork = "other_evm"
|
ChainNetworkOtherEVM ChainNetwork = "other_evm"
|
||||||
|
ChainNetworkTronMainnet ChainNetwork = "tron_mainnet"
|
||||||
|
ChainNetworkTronNile ChainNetwork = "tron_nile"
|
||||||
)
|
)
|
||||||
|
|
||||||
// InsufficientNetPolicy mirrors the fee engine policy override.
|
// InsufficientNetPolicy mirrors the fee engine policy override.
|
||||||
|
|||||||
@@ -216,6 +216,10 @@ func parseChainNetwork(value string) (chainv1.ChainNetwork, error) {
|
|||||||
return chainv1.ChainNetwork_CHAIN_NETWORK_ARBITRUM_ONE, nil
|
return chainv1.ChainNetwork_CHAIN_NETWORK_ARBITRUM_ONE, nil
|
||||||
case "OTHER_EVM", "CHAIN_NETWORK_OTHER_EVM":
|
case "OTHER_EVM", "CHAIN_NETWORK_OTHER_EVM":
|
||||||
return chainv1.ChainNetwork_CHAIN_NETWORK_OTHER_EVM, nil
|
return chainv1.ChainNetwork_CHAIN_NETWORK_OTHER_EVM, nil
|
||||||
|
case "TRON_MAINNET", "CHAIN_NETWORK_TRON_MAINNET":
|
||||||
|
return chainv1.ChainNetwork_CHAIN_NETWORK_TRON_MAINNET, nil
|
||||||
|
case "TRON_NILE", "CHAIN_NETWORK_TRON_NILE":
|
||||||
|
return chainv1.ChainNetwork_CHAIN_NETWORK_TRON_NILE, nil
|
||||||
case "", "CHAIN_NETWORK_UNSPECIFIED":
|
case "", "CHAIN_NETWORK_UNSPECIFIED":
|
||||||
return chainv1.ChainNetwork_CHAIN_NETWORK_UNSPECIFIED, merrors.InvalidArgument("chain network must be specified")
|
return chainv1.ChainNetwork_CHAIN_NETWORK_UNSPECIFIED, merrors.InvalidArgument("chain network must be specified")
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -288,6 +288,10 @@ func mapChainNetwork(chain srequest.ChainNetwork) (chainv1.ChainNetwork, error)
|
|||||||
return chainv1.ChainNetwork_CHAIN_NETWORK_ARBITRUM_ONE, nil
|
return chainv1.ChainNetwork_CHAIN_NETWORK_ARBITRUM_ONE, nil
|
||||||
case string(srequest.ChainNetworkOtherEVM):
|
case string(srequest.ChainNetworkOtherEVM):
|
||||||
return chainv1.ChainNetwork_CHAIN_NETWORK_OTHER_EVM, nil
|
return chainv1.ChainNetwork_CHAIN_NETWORK_OTHER_EVM, nil
|
||||||
|
case string(srequest.ChainNetworkTronMainnet):
|
||||||
|
return chainv1.ChainNetwork_CHAIN_NETWORK_TRON_MAINNET, nil
|
||||||
|
case string(srequest.ChainNetworkTronNile):
|
||||||
|
return chainv1.ChainNetwork_CHAIN_NETWORK_TRON_NILE, nil
|
||||||
default:
|
default:
|
||||||
return chainv1.ChainNetwork_CHAIN_NETWORK_UNSPECIFIED, merrors.InvalidArgument("unsupported chain network: " + string(chain))
|
return chainv1.ChainNetwork_CHAIN_NETWORK_UNSPECIFIED, merrors.InvalidArgument("unsupported chain network: " + string(chain))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'package:json_annotation/json_annotation.dart';
|
|||||||
|
|
||||||
part 'confirmation.g.dart';
|
part 'confirmation.g.dart';
|
||||||
|
|
||||||
|
|
||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
class ConfirmationResponse {
|
class ConfirmationResponse {
|
||||||
@JsonKey(name: 'ttl_seconds', defaultValue: 0)
|
@JsonKey(name: 'ttl_seconds', defaultValue: 0)
|
||||||
|
|||||||
@@ -90,6 +90,10 @@ ChainNetwork chainNetworkFromValue(String? value) {
|
|||||||
return ChainNetwork.arbitrumOne;
|
return ChainNetwork.arbitrumOne;
|
||||||
case 'other_evm':
|
case 'other_evm':
|
||||||
return ChainNetwork.otherEvm;
|
return ChainNetwork.otherEvm;
|
||||||
|
case 'tron_mainnet':
|
||||||
|
return ChainNetwork.tronMainnet;
|
||||||
|
case 'tron_nile':
|
||||||
|
return ChainNetwork.tronNile;
|
||||||
case 'unspecified':
|
case 'unspecified':
|
||||||
return ChainNetwork.unspecified;
|
return ChainNetwork.unspecified;
|
||||||
default:
|
default:
|
||||||
@@ -105,6 +109,10 @@ String chainNetworkToValue(ChainNetwork chain) {
|
|||||||
return 'arbitrum_one';
|
return 'arbitrum_one';
|
||||||
case ChainNetwork.otherEvm:
|
case ChainNetwork.otherEvm:
|
||||||
return 'other_evm';
|
return 'other_evm';
|
||||||
|
case ChainNetwork.tronMainnet:
|
||||||
|
return 'tron_mainnet';
|
||||||
|
case ChainNetwork.tronNile:
|
||||||
|
return 'tron_nile';
|
||||||
case ChainNetwork.unspecified:
|
case ChainNetwork.unspecified:
|
||||||
return 'unspecified';
|
return 'unspecified';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,5 +49,15 @@
|
|||||||
"chainNetworkOtherEvm": "Other EVM chain",
|
"chainNetworkOtherEvm": "Other EVM chain",
|
||||||
"@chainNetworkOtherEvm": {
|
"@chainNetworkOtherEvm": {
|
||||||
"description": "Label for any other EVM-compatible network"
|
"description": "Label for any other EVM-compatible network"
|
||||||
|
},
|
||||||
|
|
||||||
|
"chainNetworkTronMainnet": "Tron Mainnet",
|
||||||
|
"@chainNetworkTronMainnet": {
|
||||||
|
"description": "Label for the Tron mainnet network"
|
||||||
|
},
|
||||||
|
|
||||||
|
"chainNetworkTronNile": "Tron Nile (testnet)",
|
||||||
|
"@chainNetworkTronNile": {
|
||||||
|
"description": "Label for the Tron Nile testnet network"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,5 +49,15 @@
|
|||||||
"chainNetworkOtherEvm": "Другая EVM сеть",
|
"chainNetworkOtherEvm": "Другая EVM сеть",
|
||||||
"@chainNetworkOtherEvm": {
|
"@chainNetworkOtherEvm": {
|
||||||
"description": "Label for any other EVM-compatible network"
|
"description": "Label for any other EVM-compatible network"
|
||||||
|
},
|
||||||
|
|
||||||
|
"chainNetworkTronMainnet": "Tron Mainnet",
|
||||||
|
"@chainNetworkTronMainnet": {
|
||||||
|
"description": "Label for the Tron mainnet network"
|
||||||
|
},
|
||||||
|
|
||||||
|
"chainNetworkTronNile": "Tron Nile (testnet)",
|
||||||
|
"@chainNetworkTronNile": {
|
||||||
|
"description": "Label for the Tron Nile testnet network"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1,8 @@
|
|||||||
enum ChainNetwork { unspecified, ethereumMainnet, arbitrumOne, otherEvm }
|
enum ChainNetwork {
|
||||||
|
unspecified,
|
||||||
|
ethereumMainnet,
|
||||||
|
arbitrumOne,
|
||||||
|
otherEvm,
|
||||||
|
tronMainnet,
|
||||||
|
tronNile
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,6 +15,10 @@ extension ChainNetworkL10n on ChainNetwork {
|
|||||||
return l10n.chainNetworkArbitrumOne;
|
return l10n.chainNetworkArbitrumOne;
|
||||||
case ChainNetwork.otherEvm:
|
case ChainNetwork.otherEvm:
|
||||||
return l10n.chainNetworkOtherEvm;
|
return l10n.chainNetworkOtherEvm;
|
||||||
|
case ChainNetwork.tronMainnet:
|
||||||
|
return l10n.chainNetworkTronMainnet;
|
||||||
|
case ChainNetwork.tronNile:
|
||||||
|
return l10n.chainNetworkTronNile;
|
||||||
case ChainNetwork.unspecified:
|
case ChainNetwork.unspecified:
|
||||||
return l10n.chainNetworkUnspecified;
|
return l10n.chainNetworkUnspecified;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user