github.com/status-im/status-go@v1.1.0/services/wallet/requests/router_input_params.go (about) 1 package requests 2 3 import ( 4 "math/big" 5 6 "github.com/ethereum/go-ethereum/common" 7 "github.com/ethereum/go-ethereum/common/hexutil" 8 "github.com/status-im/status-go/errors" 9 "github.com/status-im/status-go/services/ens" 10 walletCommon "github.com/status-im/status-go/services/wallet/common" 11 "github.com/status-im/status-go/services/wallet/router/fees" 12 "github.com/status-im/status-go/services/wallet/router/pathprocessor" 13 "github.com/status-im/status-go/services/wallet/router/sendtype" 14 "github.com/status-im/status-go/services/wallet/token" 15 ) 16 17 var ( 18 ErrENSRegisterRequiresUsernameAndPubKey = &errors.ErrorResponse{Code: errors.ErrorCode("WRR-001"), Details: "username and public key are required for ENSRegister"} 19 ErrENSRegisterTestnetSTTOnly = &errors.ErrorResponse{Code: errors.ErrorCode("WRR-002"), Details: "only STT is supported for ENSRegister on testnet"} 20 ErrENSRegisterMainnetSNTOnly = &errors.ErrorResponse{Code: errors.ErrorCode("WRR-003"), Details: "only SNT is supported for ENSRegister on mainnet"} 21 ErrENSReleaseRequiresUsername = &errors.ErrorResponse{Code: errors.ErrorCode("WRR-004"), Details: "username is required for ENSRelease"} 22 ErrENSSetPubKeyRequiresUsernameAndPubKey = &errors.ErrorResponse{Code: errors.ErrorCode("WRR-005"), Details: "username and public key are required for ENSSetPubKey"} 23 ErrStickersBuyRequiresPackID = &errors.ErrorResponse{Code: errors.ErrorCode("WRR-006"), Details: "packID is required for StickersBuy"} 24 ErrSwapRequiresToTokenID = &errors.ErrorResponse{Code: errors.ErrorCode("WRR-007"), Details: "toTokenID is required for Swap"} 25 ErrSwapTokenIDMustBeDifferent = &errors.ErrorResponse{Code: errors.ErrorCode("WRR-008"), Details: "tokenID and toTokenID must be different"} 26 ErrSwapAmountInAmountOutMustBeExclusive = &errors.ErrorResponse{Code: errors.ErrorCode("WRR-009"), Details: "only one of amountIn or amountOut can be set"} 27 ErrSwapAmountInMustBePositive = &errors.ErrorResponse{Code: errors.ErrorCode("WRR-010"), Details: "amountIn must be positive"} 28 ErrSwapAmountOutMustBePositive = &errors.ErrorResponse{Code: errors.ErrorCode("WRR-011"), Details: "amountOut must be positive"} 29 ErrLockedAmountNotSupportedForNetwork = &errors.ErrorResponse{Code: errors.ErrorCode("WRR-012"), Details: "locked amount is not supported for the selected network"} 30 ErrLockedAmountNotNegative = &errors.ErrorResponse{Code: errors.ErrorCode("WRR-013"), Details: "locked amount must not be negative"} 31 ErrLockedAmountExceedsTotalSendAmount = &errors.ErrorResponse{Code: errors.ErrorCode("WRR-014"), Details: "locked amount exceeds the total amount to send"} 32 ErrLockedAmountLessThanSendAmountAllNetworks = &errors.ErrorResponse{Code: errors.ErrorCode("WRR-015"), Details: "locked amount is less than the total amount to send, but all networks are locked"} 33 ErrDisabledChainFoundAmongLockedNetworks = &errors.ErrorResponse{Code: errors.ErrorCode("WRR-016"), Details: "disabled chain found among locked networks"} 34 ErrENSSetPubKeyInvalidUsername = &errors.ErrorResponse{Code: errors.ErrorCode("WRR-017"), Details: "a valid username, ending in '.eth', is required for ENSSetPubKey"} 35 ErrLockedAmountExcludesAllSupported = &errors.ErrorResponse{Code: errors.ErrorCode("WRR-018"), Details: "all supported chains are excluded, routing impossible"} 36 ErrCannotCheckLockedAmounts = &errors.ErrorResponse{Code: errors.ErrorCode("WRR-019"), Details: "cannot check locked amounts"} 37 ) 38 39 type RouteInputParams struct { 40 Uuid string `json:"uuid"` 41 SendType sendtype.SendType `json:"sendType" validate:"required"` 42 AddrFrom common.Address `json:"addrFrom" validate:"required"` 43 AddrTo common.Address `json:"addrTo" validate:"required"` 44 AmountIn *hexutil.Big `json:"amountIn" validate:"required"` 45 AmountOut *hexutil.Big `json:"amountOut"` 46 TokenID string `json:"tokenID" validate:"required"` 47 ToTokenID string `json:"toTokenID"` 48 DisabledFromChainIDs []uint64 `json:"disabledFromChainIDs"` 49 DisabledToChainIDs []uint64 `json:"disabledToChainIDs"` 50 GasFeeMode fees.GasFeeMode `json:"gasFeeMode" validate:"required"` 51 FromLockedAmount map[uint64]*hexutil.Big `json:"fromLockedAmount"` 52 TestnetMode bool 53 54 // For send types like EnsRegister, EnsRelease, EnsSetPubKey, StickersBuy 55 Username string `json:"username"` 56 PublicKey string `json:"publicKey"` 57 PackID *hexutil.Big `json:"packID"` 58 59 // TODO: Remove two fields below once we implement a better solution for tests 60 // Currently used for tests only 61 TestsMode bool 62 TestParams *RouterTestParams 63 } 64 65 type RouterTestParams struct { 66 TokenFrom *token.Token 67 TokenPrices map[string]float64 68 EstimationMap map[string]pathprocessor.Estimation // [processor-name, estimation] 69 BonderFeeMap map[string]*big.Int // [token-symbol, bonder-fee] 70 SuggestedFees *fees.SuggestedFees 71 BaseFee *big.Int 72 BalanceMap map[string]*big.Int // [token-symbol, balance] 73 ApprovalGasEstimation uint64 74 ApprovalL1Fee uint64 75 } 76 77 func (i *RouteInputParams) Validate() error { 78 if i.SendType == sendtype.ENSRegister { 79 if i.Username == "" || i.PublicKey == "" { 80 return ErrENSRegisterRequiresUsernameAndPubKey 81 } 82 if i.TestnetMode { 83 if i.TokenID != pathprocessor.SttSymbol { 84 return ErrENSRegisterTestnetSTTOnly 85 } 86 } else { 87 if i.TokenID != pathprocessor.SntSymbol { 88 return ErrENSRegisterMainnetSNTOnly 89 } 90 } 91 return nil 92 } 93 94 if i.SendType == sendtype.ENSRelease { 95 if i.Username == "" { 96 return ErrENSReleaseRequiresUsername 97 } 98 } 99 100 if i.SendType == sendtype.ENSSetPubKey { 101 if i.Username == "" || i.PublicKey == "" { 102 return ErrENSSetPubKeyRequiresUsernameAndPubKey 103 } 104 105 if ens.ValidateENSUsername(i.Username) != nil { 106 return ErrENSSetPubKeyInvalidUsername 107 } 108 } 109 110 if i.SendType == sendtype.StickersBuy { 111 if i.PackID == nil { 112 return ErrStickersBuyRequiresPackID 113 } 114 } 115 116 if i.SendType == sendtype.Swap { 117 if i.ToTokenID == "" { 118 return ErrSwapRequiresToTokenID 119 } 120 if i.TokenID == i.ToTokenID { 121 return ErrSwapTokenIDMustBeDifferent 122 } 123 124 if i.AmountIn != nil && 125 i.AmountOut != nil && 126 i.AmountIn.ToInt().Cmp(pathprocessor.ZeroBigIntValue) > 0 && 127 i.AmountOut.ToInt().Cmp(pathprocessor.ZeroBigIntValue) > 0 { 128 return ErrSwapAmountInAmountOutMustBeExclusive 129 } 130 131 if i.AmountIn != nil && i.AmountIn.ToInt().Sign() < 0 { 132 return ErrSwapAmountInMustBePositive 133 } 134 135 if i.AmountOut != nil && i.AmountOut.ToInt().Sign() < 0 { 136 return ErrSwapAmountOutMustBePositive 137 } 138 } 139 140 return i.validateFromLockedAmount() 141 } 142 143 func (i *RouteInputParams) validateFromLockedAmount() error { 144 if i.FromLockedAmount == nil || len(i.FromLockedAmount) == 0 { 145 return nil 146 } 147 148 var suppNetworks map[uint64]bool 149 if i.TestnetMode { 150 suppNetworks = walletCommon.CopyMapGeneric(walletCommon.SupportedTestNetworks, nil).(map[uint64]bool) 151 } else { 152 suppNetworks = walletCommon.CopyMapGeneric(walletCommon.SupportedNetworks, nil).(map[uint64]bool) 153 } 154 155 if suppNetworks == nil { 156 return ErrCannotCheckLockedAmounts 157 } 158 159 totalLockedAmount := big.NewInt(0) 160 excludedChainCount := 0 161 162 for chainID, amount := range i.FromLockedAmount { 163 if walletCommon.ArrayContainsElement(chainID, i.DisabledFromChainIDs) { 164 return ErrDisabledChainFoundAmongLockedNetworks 165 } 166 167 if i.TestnetMode { 168 if !walletCommon.SupportedTestNetworks[chainID] { 169 return ErrLockedAmountNotSupportedForNetwork 170 } 171 } else { 172 if !walletCommon.SupportedNetworks[chainID] { 173 return ErrLockedAmountNotSupportedForNetwork 174 } 175 } 176 177 if amount == nil || amount.ToInt().Sign() < 0 { 178 return ErrLockedAmountNotNegative 179 } 180 181 if !(amount.ToInt().Sign() > 0) { 182 excludedChainCount++ 183 } 184 delete(suppNetworks, chainID) 185 totalLockedAmount = new(big.Int).Add(totalLockedAmount, amount.ToInt()) 186 } 187 188 if (!i.TestnetMode && excludedChainCount == len(walletCommon.SupportedNetworks)) || 189 (i.TestnetMode && excludedChainCount == len(walletCommon.SupportedTestNetworks)) { 190 return ErrLockedAmountExcludesAllSupported 191 } 192 193 if totalLockedAmount.Cmp(i.AmountIn.ToInt()) > 0 { 194 return ErrLockedAmountExceedsTotalSendAmount 195 } 196 if totalLockedAmount.Cmp(i.AmountIn.ToInt()) < 0 && len(suppNetworks) == 0 { 197 return ErrLockedAmountLessThanSendAmountAllNetworks 198 } 199 return nil 200 }