feat(wallet)_: refresh paraswap proposal on intervals defined per chains
This commit is contained in:
parent
b329b158c8
commit
ad56b696ed
|
@ -582,6 +582,33 @@ func (r *Router) getSelectedChains(input *requests.RouteInputParams) (selectedFr
|
||||||
return selectedFromChains, selectedToChains, nil
|
return selectedFromChains, selectedToChains, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mapRouteInputParamsToProcessorInputParams(input *requests.RouteInputParams, amountOption amountOption, fromChain *params.Network,
|
||||||
|
toChain *params.Network, token *walletToken.Token, toToken *walletToken.Token) pathprocessor.ProcessorInputParams {
|
||||||
|
processorInputParams := pathprocessor.ProcessorInputParams{
|
||||||
|
FromChain: fromChain,
|
||||||
|
ToChain: toChain,
|
||||||
|
FromToken: token,
|
||||||
|
ToToken: toToken,
|
||||||
|
ToAddr: input.AddrTo,
|
||||||
|
FromAddr: input.AddrFrom,
|
||||||
|
AmountIn: amountOption.amount,
|
||||||
|
AmountOut: input.AmountOut.ToInt(),
|
||||||
|
|
||||||
|
Username: input.Username,
|
||||||
|
PublicKey: input.PublicKey,
|
||||||
|
PackID: input.PackID.ToInt(),
|
||||||
|
}
|
||||||
|
if input.TestsMode {
|
||||||
|
processorInputParams.TestsMode = input.TestsMode
|
||||||
|
processorInputParams.TestEstimationMap = input.TestParams.EstimationMap
|
||||||
|
processorInputParams.TestBonderFeeMap = input.TestParams.BonderFeeMap
|
||||||
|
processorInputParams.TestApprovalGasEstimation = input.TestParams.ApprovalGasEstimation
|
||||||
|
processorInputParams.TestApprovalL1Fee = input.TestParams.ApprovalL1Fee
|
||||||
|
}
|
||||||
|
|
||||||
|
return processorInputParams
|
||||||
|
}
|
||||||
|
|
||||||
func (r *Router) resolveCandidates(ctx context.Context, input *requests.RouteInputParams, selectedFromChains []*params.Network,
|
func (r *Router) resolveCandidates(ctx context.Context, input *requests.RouteInputParams, selectedFromChains []*params.Network,
|
||||||
selectedToChains []*params.Network) (candidates routes.Route, processorErrors []*ProcessorError, err error) {
|
selectedToChains []*params.Network) (candidates routes.Route, processorErrors []*ProcessorError, err error) {
|
||||||
var (
|
var (
|
||||||
|
@ -694,114 +721,13 @@ func (r *Router) resolveCandidates(ctx context.Context, input *requests.RouteInp
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
processorInputParams := pathprocessor.ProcessorInputParams{
|
processorInputParams := mapRouteInputParamsToProcessorInputParams(input, amountOption, network, dest, token, toToken)
|
||||||
FromChain: network,
|
path, err := r.resolvePath(ctx, input.SendType, input.GasFeeMode, amountOption.locked, amountOption.subtractFees, processorInputParams, pProcessor, fetchedFees)
|
||||||
ToChain: dest,
|
|
||||||
FromToken: token,
|
|
||||||
ToToken: toToken,
|
|
||||||
ToAddr: input.AddrTo,
|
|
||||||
FromAddr: input.AddrFrom,
|
|
||||||
AmountIn: amountOption.amount,
|
|
||||||
AmountOut: input.AmountOut.ToInt(),
|
|
||||||
|
|
||||||
Username: input.Username,
|
|
||||||
PublicKey: input.PublicKey,
|
|
||||||
PackID: input.PackID.ToInt(),
|
|
||||||
}
|
|
||||||
if input.TestsMode {
|
|
||||||
processorInputParams.TestsMode = input.TestsMode
|
|
||||||
processorInputParams.TestEstimationMap = input.TestParams.EstimationMap
|
|
||||||
processorInputParams.TestBonderFeeMap = input.TestParams.BonderFeeMap
|
|
||||||
processorInputParams.TestApprovalGasEstimation = input.TestParams.ApprovalGasEstimation
|
|
||||||
processorInputParams.TestApprovalL1Fee = input.TestParams.ApprovalL1Fee
|
|
||||||
}
|
|
||||||
|
|
||||||
can, err := pProcessor.AvailableFor(processorInputParams)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
appendProcessorErrorFn(pProcessor.Name(), input.SendType, processorInputParams.FromChain.ChainID, processorInputParams.ToChain.ChainID, processorInputParams.AmountIn, err)
|
appendProcessorErrorFn(pProcessor.Name(), input.SendType, processorInputParams.FromChain.ChainID, processorInputParams.ToChain.ChainID, processorInputParams.AmountIn, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !can {
|
if path == nil {
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
bonderFees, tokenFees, err := pProcessor.CalculateFees(processorInputParams)
|
|
||||||
if err != nil {
|
|
||||||
appendProcessorErrorFn(pProcessor.Name(), input.SendType, processorInputParams.FromChain.ChainID, processorInputParams.ToChain.ChainID, processorInputParams.AmountIn, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
gasLimit, err := pProcessor.EstimateGas(processorInputParams)
|
|
||||||
if err != nil {
|
|
||||||
appendProcessorErrorFn(pProcessor.Name(), input.SendType, processorInputParams.FromChain.ChainID, processorInputParams.ToChain.ChainID, processorInputParams.AmountIn, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
approvalContractAddress, err := pProcessor.GetContractAddress(processorInputParams)
|
|
||||||
if err != nil {
|
|
||||||
appendProcessorErrorFn(pProcessor.Name(), input.SendType, processorInputParams.FromChain.ChainID, processorInputParams.ToChain.ChainID, processorInputParams.AmountIn, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
approvalRequired, approvalAmountRequired, err := r.requireApproval(ctx, input.SendType, &approvalContractAddress, processorInputParams)
|
|
||||||
if err != nil {
|
|
||||||
appendProcessorErrorFn(pProcessor.Name(), input.SendType, processorInputParams.FromChain.ChainID, processorInputParams.ToChain.ChainID, processorInputParams.AmountIn, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var approvalGasLimit uint64
|
|
||||||
if approvalRequired {
|
|
||||||
if processorInputParams.TestsMode {
|
|
||||||
approvalGasLimit = processorInputParams.TestApprovalGasEstimation
|
|
||||||
} else {
|
|
||||||
approvalGasLimit, err = r.estimateGasForApproval(processorInputParams, &approvalContractAddress)
|
|
||||||
if err != nil {
|
|
||||||
appendProcessorErrorFn(pProcessor.Name(), input.SendType, processorInputParams.FromChain.ChainID, processorInputParams.ToChain.ChainID, processorInputParams.AmountIn, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
amountOut, err := pProcessor.CalculateAmountOut(processorInputParams)
|
|
||||||
if err != nil {
|
|
||||||
appendProcessorErrorFn(pProcessor.Name(), input.SendType, processorInputParams.FromChain.ChainID, processorInputParams.ToChain.ChainID, processorInputParams.AmountIn, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
maxFeesPerGas := fetchedFees.FeeFor(input.GasFeeMode)
|
|
||||||
|
|
||||||
estimatedTime := r.feesManager.TransactionEstimatedTime(ctx, network.ChainID, maxFeesPerGas)
|
|
||||||
if approvalRequired && estimatedTime < fees.MoreThanFiveMinutes {
|
|
||||||
estimatedTime += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
path := &routes.Path{
|
|
||||||
ProcessorName: pProcessor.Name(),
|
|
||||||
FromChain: network,
|
|
||||||
ToChain: dest,
|
|
||||||
FromToken: token,
|
|
||||||
ToToken: toToken,
|
|
||||||
AmountIn: (*hexutil.Big)(amountOption.amount),
|
|
||||||
AmountInLocked: amountOption.locked,
|
|
||||||
AmountOut: (*hexutil.Big)(amountOut),
|
|
||||||
|
|
||||||
// set params that we don't want to be recalculated with every new block creation
|
|
||||||
TxGasAmount: gasLimit,
|
|
||||||
TxBonderFees: (*hexutil.Big)(bonderFees),
|
|
||||||
TxTokenFees: (*hexutil.Big)(tokenFees),
|
|
||||||
|
|
||||||
ApprovalRequired: approvalRequired,
|
|
||||||
ApprovalAmountRequired: (*hexutil.Big)(approvalAmountRequired),
|
|
||||||
ApprovalContractAddress: &approvalContractAddress,
|
|
||||||
ApprovalGasAmount: approvalGasLimit,
|
|
||||||
|
|
||||||
EstimatedTime: estimatedTime,
|
|
||||||
|
|
||||||
SubtractFees: amountOption.subtractFees,
|
|
||||||
}
|
|
||||||
|
|
||||||
err = r.cacluateFees(ctx, path, fetchedFees, processorInputParams.TestsMode, processorInputParams.TestApprovalL1Fee)
|
|
||||||
if err != nil {
|
|
||||||
appendProcessorErrorFn(pProcessor.Name(), input.SendType, processorInputParams.FromChain.ChainID, processorInputParams.ToChain.ChainID, processorInputParams.AmountIn, err)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -823,6 +749,92 @@ func (r *Router) resolveCandidates(ctx context.Context, input *requests.RouteInp
|
||||||
return candidates, processorErrors, nil
|
return candidates, processorErrors, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Router) resolvePath(ctx context.Context, sendType sendtype.SendType, gasFeeMode fees.GasFeeMode, amountInLocked bool, subtractFees bool,
|
||||||
|
processorInputParams pathprocessor.ProcessorInputParams, pProcessor pathprocessor.PathProcessor, fetchedFees *fees.SuggestedFees) (*routes.Path, error) {
|
||||||
|
can, err := pProcessor.AvailableFor(processorInputParams)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !can {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
bonderFees, tokenFees, err := pProcessor.CalculateFees(processorInputParams)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
gasLimit, err := pProcessor.EstimateGas(processorInputParams)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
approvalContractAddress, err := pProcessor.GetContractAddress(processorInputParams)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
approvalRequired, approvalAmountRequired, err := r.requireApproval(ctx, sendType, &approvalContractAddress, processorInputParams)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var approvalGasLimit uint64
|
||||||
|
if approvalRequired {
|
||||||
|
if processorInputParams.TestsMode {
|
||||||
|
approvalGasLimit = processorInputParams.TestApprovalGasEstimation
|
||||||
|
} else {
|
||||||
|
approvalGasLimit, err = r.estimateGasForApproval(processorInputParams, &approvalContractAddress)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
amountOut, err := pProcessor.CalculateAmountOut(processorInputParams)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
maxFeesPerGas := fetchedFees.FeeFor(gasFeeMode)
|
||||||
|
|
||||||
|
estimatedTime := r.feesManager.TransactionEstimatedTime(ctx, processorInputParams.FromChain.ChainID, maxFeesPerGas)
|
||||||
|
if approvalRequired && estimatedTime < fees.MoreThanFiveMinutes {
|
||||||
|
estimatedTime += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
path := &routes.Path{
|
||||||
|
ProcessorName: pProcessor.Name(),
|
||||||
|
FromChain: processorInputParams.FromChain,
|
||||||
|
ToChain: processorInputParams.ToChain,
|
||||||
|
FromToken: processorInputParams.FromToken,
|
||||||
|
ToToken: processorInputParams.ToToken,
|
||||||
|
AmountIn: (*hexutil.Big)(processorInputParams.AmountIn),
|
||||||
|
AmountInLocked: amountInLocked,
|
||||||
|
AmountOut: (*hexutil.Big)(amountOut),
|
||||||
|
|
||||||
|
// set params that we don't want to be recalculated with every new block creation
|
||||||
|
TxGasAmount: gasLimit,
|
||||||
|
TxBonderFees: (*hexutil.Big)(bonderFees),
|
||||||
|
TxTokenFees: (*hexutil.Big)(tokenFees),
|
||||||
|
|
||||||
|
ApprovalRequired: approvalRequired,
|
||||||
|
ApprovalAmountRequired: (*hexutil.Big)(approvalAmountRequired),
|
||||||
|
ApprovalContractAddress: &approvalContractAddress,
|
||||||
|
ApprovalGasAmount: approvalGasLimit,
|
||||||
|
|
||||||
|
EstimatedTime: estimatedTime,
|
||||||
|
|
||||||
|
SubtractFees: subtractFees,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = r.cacluateFees(ctx, path, fetchedFees, processorInputParams.TestsMode, processorInputParams.TestApprovalL1Fee)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return path, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *Router) checkBalancesForTheBestRoute(ctx context.Context, bestRoute routes.Route) (hasPositiveBalance bool, err error) {
|
func (r *Router) checkBalancesForTheBestRoute(ctx context.Context, bestRoute routes.Route) (hasPositiveBalance bool, err error) {
|
||||||
// make a copy of the active balance map
|
// make a copy of the active balance map
|
||||||
balanceMapCopy := make(map[string]*big.Int)
|
balanceMapCopy := make(map[string]*big.Int)
|
||||||
|
|
|
@ -10,14 +10,21 @@ import (
|
||||||
"github.com/status-im/status-go/logutils"
|
"github.com/status-im/status-go/logutils"
|
||||||
"github.com/status-im/status-go/rpc/chain"
|
"github.com/status-im/status-go/rpc/chain"
|
||||||
walletCommon "github.com/status-im/status-go/services/wallet/common"
|
walletCommon "github.com/status-im/status-go/services/wallet/common"
|
||||||
|
"github.com/status-im/status-go/services/wallet/router/pathprocessor"
|
||||||
|
"github.com/status-im/status-go/services/wallet/router/sendtype"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
newBlockCheckIntervalMainnet = 3 * time.Second
|
newBlockCheckIntervalMainnet = 3 * time.Second
|
||||||
newBlockCheckIntervalOptimism = 1 * time.Second
|
newBlockCheckIntervalOptimism = 2 * time.Second
|
||||||
newBlockCheckIntervalArbitrum = 200 * time.Millisecond
|
newBlockCheckIntervalArbitrum = 1 * time.Second
|
||||||
newBlockCheckIntervalAnvilMainnet = 2 * time.Second
|
newBlockCheckIntervalAnvilMainnet = 2 * time.Second
|
||||||
|
|
||||||
|
paraswapProposalCheckIntervalMainnet = 12 * time.Second
|
||||||
|
paraswapProposalCheckIntervalOptimism = 3 * time.Second
|
||||||
|
paraswapProposalCheckIntervalArbitrum = 3 * time.Second
|
||||||
|
paraswapProposalCheckIntervalAnvilMainnet = 2 * time.Second
|
||||||
|
|
||||||
feeRecalculationTimeout = 5 * time.Minute
|
feeRecalculationTimeout = 5 * time.Minute
|
||||||
feeRecalculationAnvilTimeout = 5 * time.Second
|
feeRecalculationAnvilTimeout = 5 * time.Second
|
||||||
)
|
)
|
||||||
|
@ -52,21 +59,31 @@ func (r *Router) subscribeForUdates(chainID uint64) error {
|
||||||
}
|
}
|
||||||
r.startTimeoutForUpdates(flb.closeCh, timeout)
|
r.startTimeoutForUpdates(flb.closeCh, timeout)
|
||||||
|
|
||||||
var ticker *time.Ticker
|
var (
|
||||||
|
duration time.Duration
|
||||||
|
step time.Duration
|
||||||
|
limit time.Duration
|
||||||
|
)
|
||||||
switch chainID {
|
switch chainID {
|
||||||
case walletCommon.EthereumMainnet,
|
case walletCommon.EthereumMainnet,
|
||||||
walletCommon.EthereumSepolia:
|
walletCommon.EthereumSepolia:
|
||||||
ticker = time.NewTicker(newBlockCheckIntervalMainnet)
|
step = newBlockCheckIntervalMainnet
|
||||||
|
limit = paraswapProposalCheckIntervalMainnet
|
||||||
case walletCommon.OptimismMainnet,
|
case walletCommon.OptimismMainnet,
|
||||||
walletCommon.OptimismSepolia:
|
walletCommon.OptimismSepolia:
|
||||||
ticker = time.NewTicker(newBlockCheckIntervalOptimism)
|
step = newBlockCheckIntervalOptimism
|
||||||
|
limit = paraswapProposalCheckIntervalOptimism
|
||||||
case walletCommon.ArbitrumMainnet,
|
case walletCommon.ArbitrumMainnet,
|
||||||
walletCommon.ArbitrumSepolia:
|
walletCommon.ArbitrumSepolia:
|
||||||
ticker = time.NewTicker(newBlockCheckIntervalArbitrum)
|
step = newBlockCheckIntervalArbitrum
|
||||||
|
limit = paraswapProposalCheckIntervalArbitrum
|
||||||
case walletCommon.AnvilMainnet:
|
case walletCommon.AnvilMainnet:
|
||||||
ticker = time.NewTicker(newBlockCheckIntervalAnvilMainnet)
|
step = newBlockCheckIntervalAnvilMainnet
|
||||||
|
limit = paraswapProposalCheckIntervalAnvilMainnet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ticker := time.NewTicker(step)
|
||||||
|
|
||||||
ctx, cancelCtx := context.WithCancel(context.Background())
|
ctx, cancelCtx := context.WithCancel(context.Background())
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
@ -74,6 +91,13 @@ func (r *Router) subscribeForUdates(chainID uint64) error {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
|
refreshParaswapProposal := false
|
||||||
|
duration += step
|
||||||
|
if duration >= limit {
|
||||||
|
refreshParaswapProposal = true
|
||||||
|
duration = 0
|
||||||
|
}
|
||||||
|
|
||||||
var blockNumber uint64
|
var blockNumber uint64
|
||||||
blockNumber, err := ethClient.BlockNumber(ctx)
|
blockNumber, err := ethClient.BlockNumber(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -103,23 +127,37 @@ func (r *Router) subscribeForUdates(chainID uint64) error {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
r.lastInputParamsMutex.Lock()
|
_, inputParams := r.GetBestRouteAndAssociatedInputParams()
|
||||||
uuid := r.lastInputParams.Uuid
|
|
||||||
r.lastInputParamsMutex.Unlock()
|
|
||||||
|
|
||||||
r.activeRoutesMutex.Lock()
|
r.activeRoutesMutex.Lock()
|
||||||
if r.activeRoutes != nil && r.activeRoutes.Best != nil && len(r.activeRoutes.Best) > 0 {
|
if r.activeRoutes != nil && r.activeRoutes.Best != nil && len(r.activeRoutes.Best) > 0 {
|
||||||
for _, path := range r.activeRoutes.Best {
|
for i, path := range r.activeRoutes.Best {
|
||||||
err = r.cacluateFees(ctx, path, fees, false, 0)
|
if path.ProcessorName == pathprocessor.ProcessorSwapParaswapName && refreshParaswapProposal {
|
||||||
if err != nil {
|
amountOption := amountOption{
|
||||||
logutils.ZapLogger().Error("Failed to calculate fees", zap.Error(err))
|
amount: path.AmountIn.ToInt(),
|
||||||
continue
|
locked: path.AmountInLocked,
|
||||||
|
subtractFees: path.SubtractFees,
|
||||||
|
}
|
||||||
|
processorInputParams := mapRouteInputParamsToProcessorInputParams(&inputParams, amountOption, path.FromChain, path.ToChain, path.FromToken, path.ToToken)
|
||||||
|
swapProcessor := r.pathProcessors[path.ProcessorName]
|
||||||
|
newPath, err := r.resolvePath(ctx, sendtype.Swap, inputParams.GasFeeMode, amountOption.locked, amountOption.subtractFees, processorInputParams, swapProcessor, fees)
|
||||||
|
if err != nil {
|
||||||
|
logutils.ZapLogger().Error("Failed to calculate fees", zap.Error(err))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
r.activeRoutes.Best[i] = newPath
|
||||||
|
} else {
|
||||||
|
err = r.cacluateFees(ctx, path, fees, false, 0)
|
||||||
|
if err != nil {
|
||||||
|
logutils.ZapLogger().Error("Failed to calculate fees", zap.Error(err))
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = r.checkBalancesForTheBestRoute(ctx, r.activeRoutes.Best)
|
_, err = r.checkBalancesForTheBestRoute(ctx, r.activeRoutes.Best)
|
||||||
|
|
||||||
sendRouterResult(uuid, r.activeRoutes, err)
|
sendRouterResult(inputParams.Uuid, r.activeRoutes, err)
|
||||||
}
|
}
|
||||||
r.activeRoutesMutex.Unlock()
|
r.activeRoutesMutex.Unlock()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue