gas tanking before transaction

This commit is contained in:
Stephan D
2025-12-25 11:25:13 +01:00
parent 0505b2314e
commit d46822b9bb
24 changed files with 1283 additions and 160 deletions

View File

@@ -95,9 +95,13 @@ func (c *estimateTransferFeeCommand) Execute(ctx context.Context, req *chainv1.E
return gsresponse.Auto[chainv1.EstimateTransferFeeResponse](c.deps.Logger, mservice.ChainGateway, err)
}
contextLabel := "erc20_transfer"
if strings.TrimSpace(sourceWallet.ContractAddress) == "" {
contextLabel = "native_transfer"
}
resp := &chainv1.EstimateTransferFeeResponse{
NetworkFee: feeMoney,
EstimationContext: "erc20_transfer",
EstimationContext: contextLabel,
}
return gsresponse.Success(resp)
}

View File

@@ -51,7 +51,7 @@ func (c *getWalletBalanceCommand) Execute(ctx context.Context, req *chainv1.GetW
return gsresponse.Auto[chainv1.GetWalletBalanceResponse](c.deps.Logger, mservice.ChainGateway, err)
}
balance, chainErr := onChainWalletBalance(ctx, c.deps, wallet)
tokenBalance, nativeBalance, chainErr := onChainWalletBalances(ctx, c.deps, wallet)
if chainErr != nil {
c.deps.Logger.Warn("on-chain balance fetch failed, attempting cached balance", zap.Error(chainErr), zap.String("wallet_ref", walletRef))
stored, err := c.deps.Storage.Wallets().GetBalance(ctx, walletRef)
@@ -74,37 +74,47 @@ func (c *getWalletBalanceCommand) Execute(ctx context.Context, req *chainv1.GetW
}
calculatedAt := c.now()
c.persistCachedBalance(ctx, walletRef, balance, calculatedAt)
c.persistCachedBalance(ctx, walletRef, tokenBalance, nativeBalance, calculatedAt)
return gsresponse.Success(&chainv1.GetWalletBalanceResponse{
Balance: onChainBalanceToProto(balance, calculatedAt),
Balance: onChainBalanceToProto(tokenBalance, nativeBalance, calculatedAt),
})
}
func onChainBalanceToProto(balance *moneyv1.Money, calculatedAt time.Time) *chainv1.WalletBalance {
if balance == nil {
func onChainBalanceToProto(balance *moneyv1.Money, native *moneyv1.Money, calculatedAt time.Time) *chainv1.WalletBalance {
if balance == nil && native == nil {
return nil
}
zero := zeroMoney(balance.Currency)
currency := ""
if balance != nil {
currency = balance.Currency
}
zero := zeroMoney(currency)
return &chainv1.WalletBalance{
Available: balance,
NativeAvailable: native,
PendingInbound: zero,
PendingOutbound: zero,
CalculatedAt: timestamppb.New(calculatedAt.UTC()),
}
}
func (c *getWalletBalanceCommand) persistCachedBalance(ctx context.Context, walletRef string, available *moneyv1.Money, calculatedAt time.Time) {
if available == nil {
func (c *getWalletBalanceCommand) persistCachedBalance(ctx context.Context, walletRef string, available *moneyv1.Money, nativeAvailable *moneyv1.Money, calculatedAt time.Time) {
if available == nil && nativeAvailable == nil {
return
}
record := &model.WalletBalance{
WalletRef: walletRef,
Available: shared.CloneMoney(available),
PendingInbound: zeroMoney(available.Currency),
PendingOutbound: zeroMoney(available.Currency),
NativeAvailable: shared.CloneMoney(nativeAvailable),
CalculatedAt: calculatedAt,
}
currency := ""
if available != nil {
currency = available.Currency
}
record.PendingInbound = zeroMoney(currency)
record.PendingOutbound = zeroMoney(currency)
if err := c.deps.Storage.Wallets().SaveBalance(ctx, record); err != nil {
c.deps.Logger.Warn("failed to cache wallet balance", zap.String("wallet_ref", walletRef), zap.Error(err))
}

View File

@@ -82,10 +82,12 @@ func (c *createManagedWalletCommand) Execute(ctx context.Context, req *chainv1.C
}
contractAddress := strings.ToLower(strings.TrimSpace(asset.GetContractAddress()))
if contractAddress == "" {
contractAddress = shared.ResolveContractAddress(networkCfg.TokenConfigs, tokenSymbol)
if contractAddress == "" {
c.deps.Logger.Warn("unsupported token", zap.String("token", tokenSymbol), zap.String("chain", chainKey))
return gsresponse.InvalidArgument[chainv1.CreateManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("unsupported token for chain"))
if !strings.EqualFold(tokenSymbol, networkCfg.NativeToken) {
contractAddress = shared.ResolveContractAddress(networkCfg.TokenConfigs, tokenSymbol)
if contractAddress == "" {
c.deps.Logger.Warn("unsupported token", zap.String("token", tokenSymbol), zap.String("chain", chainKey))
return gsresponse.InvalidArgument[chainv1.CreateManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("unsupported token for chain"))
}
}
}

View File

@@ -12,16 +12,16 @@ import (
"go.uber.org/zap"
)
func onChainWalletBalance(ctx context.Context, deps Deps, wallet *model.ManagedWallet) (*moneyv1.Money, error) {
func onChainWalletBalances(ctx context.Context, deps Deps, wallet *model.ManagedWallet) (*moneyv1.Money, *moneyv1.Money, error) {
logger := deps.Logger
if wallet == nil {
return nil, merrors.InvalidArgument("wallet is required")
return nil, nil, merrors.InvalidArgument("wallet is required")
}
if deps.Networks == nil {
return nil, merrors.Internal("rpc clients not initialised")
return nil, nil, merrors.Internal("rpc clients not initialised")
}
if deps.Drivers == nil {
return nil, merrors.Internal("chain drivers not configured")
return nil, nil, merrors.Internal("chain drivers not configured")
}
networkKey := strings.ToLower(strings.TrimSpace(wallet.Network))
@@ -31,7 +31,7 @@ func onChainWalletBalance(ctx context.Context, deps Deps, wallet *model.ManagedW
zap.String("wallet_ref", wallet.WalletRef),
zap.String("network", networkKey),
)
return nil, merrors.Internal(fmt.Sprintf("Requested network '%s' is not configured", networkKey))
return nil, nil, merrors.Internal(fmt.Sprintf("Requested network '%s' is not configured", networkKey))
}
chainDriver, err := deps.Drivers.Driver(networkKey)
@@ -41,7 +41,7 @@ func onChainWalletBalance(ctx context.Context, deps Deps, wallet *model.ManagedW
zap.String("network", networkKey),
zap.Error(err),
)
return nil, merrors.InvalidArgument("unsupported chain")
return nil, nil, merrors.InvalidArgument("unsupported chain")
}
driverDeps := driver.Deps{
@@ -50,5 +50,13 @@ func onChainWalletBalance(ctx context.Context, deps Deps, wallet *model.ManagedW
KeyManager: deps.KeyManager,
RPCTimeout: deps.RPCTimeout,
}
return chainDriver.Balance(ctx, driverDeps, network, wallet)
tokenBalance, err := chainDriver.Balance(ctx, driverDeps, network, wallet)
if err != nil {
return nil, nil, err
}
nativeBalance, err := chainDriver.NativeBalance(ctx, driverDeps, network, wallet)
if err != nil {
return nil, nil, err
}
return tokenBalance, nativeBalance, nil
}

View File

@@ -58,6 +58,7 @@ func toProtoWalletBalance(balance *model.WalletBalance) *chainv1.WalletBalance {
}
return &chainv1.WalletBalance{
Available: shared.CloneMoney(balance.Available),
NativeAvailable: shared.CloneMoney(balance.NativeAvailable),
PendingInbound: shared.CloneMoney(balance.PendingInbound),
PendingOutbound: shared.CloneMoney(balance.PendingOutbound),
CalculatedAt: timestamppb.New(balance.CalculatedAt.UTC()),