feat_: new endpoint added for an async route/s calculation
- `GetSuggestedRoutesV2Async` calculates the route/s based on input parameters and sends `wallet.suggested.routes` signal to notify a client.
This commit is contained in:
parent
8bcb6ce667
commit
92361d9e20
|
@ -94,6 +94,7 @@ func (api *API) StartWallet(ctx context.Context) error {
|
|||
}
|
||||
|
||||
func (api *API) StopWallet(ctx context.Context) error {
|
||||
api.router.Stop()
|
||||
return api.s.Stop()
|
||||
}
|
||||
|
||||
|
@ -509,6 +510,18 @@ func (api *API) GetSuggestedRoutesV2(ctx context.Context, input *router.RouteInp
|
|||
return api.router.SuggestedRoutesV2(ctx, input)
|
||||
}
|
||||
|
||||
func (api *API) GetSuggestedRoutesV2Async(ctx context.Context, input *router.RouteInputParams) {
|
||||
log.Debug("call to GetSuggestedRoutesV2Async")
|
||||
|
||||
api.router.SuggestedRoutesV2Async(input)
|
||||
}
|
||||
|
||||
func (api *API) StopSuggestedRoutesV2AsyncCalcualtion(ctx context.Context) {
|
||||
log.Debug("call to StopSuggestedRoutesV2AsyncCalcualtion")
|
||||
|
||||
api.router.StopSuggestedRoutesV2AsyncCalcualtion()
|
||||
}
|
||||
|
||||
// Generates addresses for the provided paths, response doesn't include `HasActivity` value (if you need it check `GetAddressDetails` function)
|
||||
func (api *API) GetDerivedAddresses(ctx context.Context, password string, derivedFrom string, paths []string) ([]*DerivedAddress, error) {
|
||||
info, err := api.s.gethManager.AccountsGenerator().LoadAccount(derivedFrom, password)
|
||||
|
|
|
@ -24,4 +24,5 @@ var (
|
|||
ErrNotEnoughTokenBalance = &errors.ErrorResponse{Code: errors.ErrorCode("WR-016"), Details: "not enough token balance"}
|
||||
ErrNotEnoughNativeBalance = &errors.ErrorResponse{Code: errors.ErrorCode("WR-017"), Details: "not enough native balance"}
|
||||
ErrNativeTokenNotFound = &errors.ErrorResponse{Code: errors.ErrorCode("WR-018"), Details: "native token not found"}
|
||||
ErrDisabledChainFoundAmongLockedNetworks = &errors.ErrorResponse{Code: errors.ErrorCode("WR-019"), Details: "disabled chain found among locked networks"}
|
||||
)
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/consensus/misc"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
gaspriceoracle "github.com/status-im/status-go/contracts/gas-price-oracle"
|
||||
|
@ -25,9 +26,9 @@ const (
|
|||
)
|
||||
|
||||
type MaxFeesLevels struct {
|
||||
Low *big.Int `json:"low"`
|
||||
Medium *big.Int `json:"medium"`
|
||||
High *big.Int `json:"high"`
|
||||
Low *hexutil.Big `json:"low"`
|
||||
Medium *hexutil.Big `json:"medium"`
|
||||
High *hexutil.Big `json:"high"`
|
||||
}
|
||||
|
||||
type SuggestedFees struct {
|
||||
|
@ -59,14 +60,14 @@ func (s *SuggestedFees) feeFor(mode GasFeeMode) *big.Int {
|
|||
}
|
||||
|
||||
if mode == GasFeeLow {
|
||||
return s.MaxFeesLevels.Low
|
||||
return s.MaxFeesLevels.Low.ToInt()
|
||||
}
|
||||
|
||||
if mode == GasFeeHigh {
|
||||
return s.MaxFeesLevels.High
|
||||
return s.MaxFeesLevels.High.ToInt()
|
||||
}
|
||||
|
||||
return s.MaxFeesLevels.Medium
|
||||
return s.MaxFeesLevels.Medium.ToInt()
|
||||
}
|
||||
|
||||
func (s *SuggestedFeesGwei) feeFor(mode GasFeeMode) *big.Float {
|
||||
|
@ -140,9 +141,9 @@ func (f *FeeManager) SuggestedFees(ctx context.Context, chainID uint64) (*Sugges
|
|||
BaseFee: big.NewInt(0),
|
||||
MaxPriorityFeePerGas: big.NewInt(0),
|
||||
MaxFeesLevels: &MaxFeesLevels{
|
||||
Low: big.NewInt(0),
|
||||
Medium: big.NewInt(0),
|
||||
High: big.NewInt(0),
|
||||
Low: (*hexutil.Big)(big.NewInt(0)),
|
||||
Medium: (*hexutil.Big)(big.NewInt(0)),
|
||||
High: (*hexutil.Big)(big.NewInt(0)),
|
||||
},
|
||||
EIP1559Enabled: false,
|
||||
}, nil
|
||||
|
@ -158,9 +159,9 @@ func (f *FeeManager) SuggestedFees(ctx context.Context, chainID uint64) (*Sugges
|
|||
BaseFee: baseFee,
|
||||
MaxPriorityFeePerGas: maxPriorityFeePerGas,
|
||||
MaxFeesLevels: &MaxFeesLevels{
|
||||
Low: new(big.Int).Add(baseFee, maxPriorityFeePerGas),
|
||||
Medium: new(big.Int).Add(new(big.Int).Mul(baseFee, big.NewInt(2)), maxPriorityFeePerGas),
|
||||
High: new(big.Int).Add(new(big.Int).Mul(baseFee, big.NewInt(3)), maxPriorityFeePerGas),
|
||||
Low: (*hexutil.Big)(new(big.Int).Add(baseFee, maxPriorityFeePerGas)),
|
||||
Medium: (*hexutil.Big)(new(big.Int).Add(new(big.Int).Mul(baseFee, big.NewInt(2)), maxPriorityFeePerGas)),
|
||||
High: (*hexutil.Big)(new(big.Int).Add(new(big.Int).Mul(baseFee, big.NewInt(3)), maxPriorityFeePerGas)),
|
||||
},
|
||||
EIP1559Enabled: true,
|
||||
}, nil
|
||||
|
@ -175,9 +176,9 @@ func (f *FeeManager) SuggestedFeesGwei(ctx context.Context, chainID uint64) (*Su
|
|||
GasPrice: weiToGwei(fees.GasPrice),
|
||||
BaseFee: weiToGwei(fees.BaseFee),
|
||||
MaxPriorityFeePerGas: weiToGwei(fees.MaxPriorityFeePerGas),
|
||||
MaxFeePerGasLow: weiToGwei(fees.MaxFeesLevels.Low),
|
||||
MaxFeePerGasMedium: weiToGwei(fees.MaxFeesLevels.Medium),
|
||||
MaxFeePerGasHigh: weiToGwei(fees.MaxFeesLevels.High),
|
||||
MaxFeePerGasLow: weiToGwei(fees.MaxFeesLevels.Low.ToInt()),
|
||||
MaxFeePerGasMedium: weiToGwei(fees.MaxFeesLevels.Medium.ToInt()),
|
||||
MaxFeePerGasHigh: weiToGwei(fees.MaxFeesLevels.High.ToInt()),
|
||||
EIP1559Enabled: fees.EIP1559Enabled,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
@ -288,6 +288,7 @@ func NewRouter(rpcClient *rpc.Client, transactor *transactions.Transactor, token
|
|||
stickersService: stickersService,
|
||||
feesManager: &FeeManager{rpcClient},
|
||||
pathProcessors: processors,
|
||||
scheduler: async.NewScheduler(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -295,6 +296,10 @@ func (r *Router) AddPathProcessor(processor pathprocessor.PathProcessor) {
|
|||
r.pathProcessors[processor.Name()] = processor
|
||||
}
|
||||
|
||||
func (r *Router) Stop() {
|
||||
r.scheduler.Stop()
|
||||
}
|
||||
|
||||
func (r *Router) GetFeesManager() *FeeManager {
|
||||
return r.feesManager
|
||||
}
|
||||
|
@ -303,9 +308,9 @@ func (r *Router) GetPathProcessors() map[string]pathprocessor.PathProcessor {
|
|||
return r.pathProcessors
|
||||
}
|
||||
|
||||
func containsNetworkChainID(network *params.Network, chainIDs []uint64) bool {
|
||||
for _, chainID := range chainIDs {
|
||||
if chainID == network.ChainID {
|
||||
func containsNetworkChainID(chainID uint64, chainIDs []uint64) bool {
|
||||
for _, cID := range chainIDs {
|
||||
if cID == chainID {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -323,6 +328,7 @@ type Router struct {
|
|||
stickersService *stickers.Service
|
||||
feesManager *FeeManager
|
||||
pathProcessors map[string]pathprocessor.PathProcessor
|
||||
scheduler *async.Scheduler
|
||||
}
|
||||
|
||||
func (r *Router) requireApproval(ctx context.Context, sendType SendType, approvalContractAddress *common.Address, params pathprocessor.ProcessorInputParams) (
|
||||
|
@ -478,7 +484,7 @@ func (r *Router) SuggestedRoutes(
|
|||
continue
|
||||
}
|
||||
|
||||
if containsNetworkChainID(network, disabledFromChainIDs) {
|
||||
if containsNetworkChainID(network.ChainID, disabledFromChainIDs) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -562,10 +568,10 @@ func (r *Router) SuggestedRoutes(
|
|||
continue
|
||||
}
|
||||
|
||||
if len(preferedChainIDs) > 0 && !containsNetworkChainID(dest, preferedChainIDs) {
|
||||
if len(preferedChainIDs) > 0 && !containsNetworkChainID(dest.ChainID, preferedChainIDs) {
|
||||
continue
|
||||
}
|
||||
if containsNetworkChainID(dest, disabledToChainIDs) {
|
||||
if containsNetworkChainID(dest.ChainID, disabledToChainIDs) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -710,6 +716,9 @@ func (r *Router) SuggestedRoutes(
|
|||
FromToken: &token.Token{
|
||||
Symbol: tokenID,
|
||||
},
|
||||
ToToken: &token.Token{
|
||||
Symbol: toTokenID,
|
||||
},
|
||||
}
|
||||
|
||||
amountOut, err := r.pathProcessors[path.BridgeName].CalculateAmountOut(processorInputParams)
|
||||
|
|
|
@ -16,6 +16,14 @@ import (
|
|||
walletCommon "github.com/status-im/status-go/services/wallet/common"
|
||||
"github.com/status-im/status-go/services/wallet/router/pathprocessor"
|
||||
walletToken "github.com/status-im/status-go/services/wallet/token"
|
||||
"github.com/status-im/status-go/signal"
|
||||
)
|
||||
|
||||
var (
|
||||
routerTask = async.TaskType{
|
||||
ID: 1,
|
||||
Policy: async.ReplacementPolicyCancelOld,
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -33,6 +41,7 @@ var (
|
|||
)
|
||||
|
||||
type RouteInputParams struct {
|
||||
Uuid string `json:"uuid"`
|
||||
SendType SendType `json:"sendType" validate:"required"`
|
||||
AddrFrom common.Address `json:"addrFrom" validate:"required"`
|
||||
AddrTo common.Address `json:"addrTo" validate:"required"`
|
||||
|
@ -106,12 +115,18 @@ func (p *PathV2) Equal(o *PathV2) bool {
|
|||
}
|
||||
|
||||
type SuggestedRoutesV2 struct {
|
||||
Uuid string
|
||||
Best []*PathV2
|
||||
Candidates []*PathV2
|
||||
TokenPrice float64
|
||||
NativeChainTokenPrice float64
|
||||
}
|
||||
|
||||
type ErrorResponseWithUUID struct {
|
||||
Uuid string
|
||||
ErrorResponse error
|
||||
}
|
||||
|
||||
type GraphV2 = []*NodeV2
|
||||
|
||||
type NodeV2 struct {
|
||||
|
@ -120,6 +135,7 @@ type NodeV2 struct {
|
|||
}
|
||||
|
||||
func newSuggestedRoutesV2(
|
||||
uuid string,
|
||||
amountIn *big.Int,
|
||||
candidates []*PathV2,
|
||||
fromLockedAmount map[uint64]*hexutil.Big,
|
||||
|
@ -127,6 +143,7 @@ func newSuggestedRoutesV2(
|
|||
nativeChainTokenPrice float64,
|
||||
) *SuggestedRoutesV2 {
|
||||
suggestedRoutes := &SuggestedRoutesV2{
|
||||
Uuid: uuid,
|
||||
Candidates: candidates,
|
||||
Best: candidates,
|
||||
TokenPrice: tokenPrice,
|
||||
|
@ -388,6 +405,9 @@ func validateInputData(input *RouteInputParams) error {
|
|||
totalLockedAmount := big.NewInt(0)
|
||||
|
||||
for chainID, amount := range input.FromLockedAmount {
|
||||
if containsNetworkChainID(chainID, input.DisabledFromChainIDs) {
|
||||
return ErrDisabledChainFoundAmongLockedNetworks
|
||||
}
|
||||
if input.testnetMode {
|
||||
if !supportedTestNetworks[chainID] {
|
||||
return ErrLockedAmountNotSupportedForNetwork
|
||||
|
@ -417,7 +437,34 @@ func validateInputData(input *RouteInputParams) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (r *Router) SuggestedRoutesV2Async(input *RouteInputParams) {
|
||||
r.scheduler.Enqueue(routerTask, func(ctx context.Context) (interface{}, error) {
|
||||
return r.SuggestedRoutesV2(ctx, input)
|
||||
}, func(result interface{}, taskType async.TaskType, err error) {
|
||||
if err != nil {
|
||||
errResponse := &ErrorResponseWithUUID{
|
||||
Uuid: input.Uuid,
|
||||
ErrorResponse: errors.CreateErrorResponseFromError(err),
|
||||
}
|
||||
signal.SendWalletEvent(signal.SuggestedRoutes, errResponse)
|
||||
return
|
||||
}
|
||||
signal.SendWalletEvent(signal.SuggestedRoutes, result)
|
||||
})
|
||||
}
|
||||
|
||||
func (r *Router) StopSuggestedRoutesV2AsyncCalcualtion() {
|
||||
r.scheduler.Stop()
|
||||
}
|
||||
|
||||
func (r *Router) SuggestedRoutesV2(ctx context.Context, input *RouteInputParams) (*SuggestedRoutesV2, error) {
|
||||
testnetMode, err := r.rpcClient.NetworkManager.GetTestNetworksEnabled()
|
||||
if err != nil {
|
||||
return nil, errors.CreateErrorResponseFromError(err)
|
||||
}
|
||||
|
||||
input.testnetMode = testnetMode
|
||||
|
||||
// clear all processors
|
||||
for _, processor := range r.pathProcessors {
|
||||
if clearable, ok := processor.(pathprocessor.PathProcessorClearable); ok {
|
||||
|
@ -425,18 +472,11 @@ func (r *Router) SuggestedRoutesV2(ctx context.Context, input *RouteInputParams)
|
|||
}
|
||||
}
|
||||
|
||||
err := validateInputData(input)
|
||||
err = validateInputData(input)
|
||||
if err != nil {
|
||||
return nil, errors.CreateErrorResponseFromError(err)
|
||||
}
|
||||
|
||||
testnetMode, err := r.rpcClient.NetworkManager.GetTestNetworksEnabled()
|
||||
if err != nil {
|
||||
return nil, errors.CreateErrorResponseFromError(err)
|
||||
}
|
||||
|
||||
input.testnetMode = testnetMode
|
||||
|
||||
candidates, err := r.resolveCandidates(ctx, input)
|
||||
if err != nil {
|
||||
return nil, errors.CreateErrorResponseFromError(err)
|
||||
|
@ -467,7 +507,7 @@ func (r *Router) resolveCandidates(ctx context.Context, input *RouteInputParams)
|
|||
continue
|
||||
}
|
||||
|
||||
if containsNetworkChainID(network, input.DisabledFromChainIDs) {
|
||||
if containsNetworkChainID(network.ChainID, input.DisabledFromChainIDs) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -507,11 +547,17 @@ func (r *Router) resolveCandidates(ctx context.Context, input *RouteInputParams)
|
|||
}
|
||||
}
|
||||
|
||||
group.Add(func(c context.Context) error {
|
||||
var fees *SuggestedFees
|
||||
if testsMode {
|
||||
fees = input.testParams.suggestedFees
|
||||
} else {
|
||||
fees, err = r.feesManager.SuggestedFees(ctx, network.ChainID)
|
||||
if err != nil {
|
||||
return errors.CreateErrorResponseFromError(err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
group.Add(func(c context.Context) error {
|
||||
for _, pProcessor := range r.pathProcessors {
|
||||
// With the condition below we're eliminating `Swap` as potential path that can participate in calculating the best route
|
||||
// once we decide to inlcude `Swap` in the calculation we need to update `canUseProcessor` function.
|
||||
|
@ -546,7 +592,7 @@ func (r *Router) resolveCandidates(ctx context.Context, input *RouteInputParams)
|
|||
continue
|
||||
}
|
||||
|
||||
if containsNetworkChainID(dest, input.DisabledToChainIDs) {
|
||||
if containsNetworkChainID(dest.ChainID, input.DisabledToChainIDs) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -558,7 +604,7 @@ func (r *Router) resolveCandidates(ctx context.Context, input *RouteInputParams)
|
|||
ToAddr: input.AddrTo,
|
||||
FromAddr: input.AddrFrom,
|
||||
AmountIn: amountToSend,
|
||||
AmountOut: amountToSend,
|
||||
AmountOut: input.AmountOut.ToInt(),
|
||||
|
||||
Username: input.Username,
|
||||
PublicKey: input.PublicKey,
|
||||
|
@ -606,16 +652,6 @@ func (r *Router) resolveCandidates(ctx context.Context, input *RouteInputParams)
|
|||
l1FeeWei, _ = r.feesManager.GetL1Fee(ctx, network.ChainID, txInputData)
|
||||
}
|
||||
|
||||
var fees *SuggestedFees
|
||||
if testsMode {
|
||||
fees = input.testParams.suggestedFees
|
||||
} else {
|
||||
fees, err = r.feesManager.SuggestedFees(ctx, network.ChainID)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
amountOut, err := pProcessor.CalculateAmountOut(processorInputParams)
|
||||
if err != nil {
|
||||
continue
|
||||
|
@ -679,7 +715,7 @@ func (r *Router) resolveRoutes(ctx context.Context, input *RouteInputParams, can
|
|||
}
|
||||
}
|
||||
|
||||
suggestedRoutes = newSuggestedRoutesV2(input.AmountIn.ToInt(), candidates, input.FromLockedAmount, prices[input.TokenID], prices[pathprocessor.EthSymbol])
|
||||
suggestedRoutes = newSuggestedRoutesV2(input.Uuid, input.AmountIn.ToInt(), candidates, input.FromLockedAmount, prices[input.TokenID], prices[pathprocessor.EthSymbol])
|
||||
|
||||
// check the best route for the required balances
|
||||
for _, path := range suggestedRoutes.Best {
|
||||
|
@ -693,12 +729,12 @@ func (r *Router) resolveRoutes(ctx context.Context, input *RouteInputParams, can
|
|||
if input.SendType == ERC1155Transfer {
|
||||
tokenBalance, err = r.getERC1155Balance(ctx, path.FromChain, path.FromToken, input.AddrFrom)
|
||||
if err != nil {
|
||||
return nil, errors.CreateErrorResponseFromError(err)
|
||||
return suggestedRoutes, errors.CreateErrorResponseFromError(err)
|
||||
}
|
||||
} else if input.SendType != ERC721Transfer {
|
||||
tokenBalance, err = r.getBalance(ctx, path.FromChain, path.FromToken, input.AddrFrom)
|
||||
if err != nil {
|
||||
return nil, errors.CreateErrorResponseFromError(err)
|
||||
return suggestedRoutes, errors.CreateErrorResponseFromError(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -716,12 +752,12 @@ func (r *Router) resolveRoutes(ctx context.Context, input *RouteInputParams, can
|
|||
} else {
|
||||
nativeToken := r.tokenManager.FindToken(path.FromChain, path.FromChain.NativeCurrencySymbol)
|
||||
if nativeToken == nil {
|
||||
return nil, ErrNativeTokenNotFound
|
||||
return suggestedRoutes, ErrNativeTokenNotFound
|
||||
}
|
||||
|
||||
nativeBalance, err = r.getBalance(ctx, path.FromChain, nativeToken, input.AddrFrom)
|
||||
if err != nil {
|
||||
return nil, errors.CreateErrorResponseFromError(err)
|
||||
return suggestedRoutes, errors.CreateErrorResponseFromError(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -67,9 +67,9 @@ var (
|
|||
BaseFee: big.NewInt(testBaseFee),
|
||||
MaxPriorityFeePerGas: big.NewInt(testPriorityFeeLow),
|
||||
MaxFeesLevels: &MaxFeesLevels{
|
||||
Low: big.NewInt(testPriorityFeeLow),
|
||||
Medium: big.NewInt(testPriorityFeeMedium),
|
||||
High: big.NewInt(testPriorityFeeHigh),
|
||||
Low: (*hexutil.Big)(big.NewInt(testPriorityFeeLow)),
|
||||
Medium: (*hexutil.Big)(big.NewInt(testPriorityFeeMedium)),
|
||||
High: (*hexutil.Big)(big.NewInt(testPriorityFeeHigh)),
|
||||
},
|
||||
EIP1559Enabled: false,
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ type SignalType string
|
|||
const (
|
||||
Wallet = SignalType("wallet")
|
||||
SignTransactions = SignalType("wallet.sign.transactions")
|
||||
SuggestedRoutes = SignalType("wallet.suggested.routes")
|
||||
)
|
||||
|
||||
// SendWalletEvent sends event from services/wallet/events.
|
||||
|
|
Loading…
Reference in New Issue