github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/tequilapi/contract/transactor.go (about) 1 /* 2 * Copyright (C) 2020 The "MysteriumNetwork/node" Authors. 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 package contract 19 20 import ( 21 "fmt" 22 "math/big" 23 "net/http" 24 "time" 25 26 "github.com/mysteriumnetwork/go-rest/apierror" 27 "github.com/mysteriumnetwork/node/core/beneficiary" 28 "github.com/mysteriumnetwork/node/identity/registry" 29 "github.com/mysteriumnetwork/payments/crypto" 30 31 "github.com/ethereum/go-ethereum/common" 32 "github.com/go-openapi/strfmt" 33 "github.com/mysteriumnetwork/node/identity" 34 "github.com/mysteriumnetwork/node/session/pingpong" 35 "github.com/mysteriumnetwork/node/tequilapi/utils" 36 ) 37 38 // FeesDTO represents the transactor fees 39 // swagger:model FeesDTO 40 type FeesDTO struct { 41 Registration *big.Int `json:"registration"` 42 RegistrationTokens Tokens `json:"registration_tokens"` 43 Settlement *big.Int `json:"settlement"` 44 SettlementTokens Tokens `json:"settlement_tokens"` 45 // deprecated - confusing name 46 Hermes uint16 `json:"hermes"` 47 HermesPercent string `json:"hermes_percent"` 48 DecreaseStake *big.Int `json:"decreaseStake"` 49 DecreaseStakeTokens Tokens `json:"decrease_stake_tokens"` 50 } 51 52 // CombinedFeesResponse represents transactor fees. 53 // swagger:model CombinedFeesResponse 54 type CombinedFeesResponse struct { 55 Current TransactorFees `json:"current"` 56 Last TransactorFees `json:"last"` 57 58 ServerTime time.Time `json:"server_time"` 59 HermesPercent string `json:"hermes_percent"` 60 } 61 62 // TransactorFees represents transactor fees. 63 // swagger:model TransactorFees 64 type TransactorFees struct { 65 Registration Tokens `json:"registration"` 66 Settlement Tokens `json:"settlement"` 67 DecreaseStake Tokens `json:"decrease_stake"` 68 69 ValidUntil time.Time `json:"valid_until"` 70 } 71 72 // NewTransactorFees converts registry fees to public api. 73 func NewTransactorFees(r *registry.Fees) TransactorFees { 74 return TransactorFees{ 75 Registration: NewTokens(r.Register), 76 Settlement: NewTokens(r.Settle), 77 DecreaseStake: NewTokens(r.DecreaseStake), 78 ValidUntil: r.ValidUntil, 79 } 80 } 81 82 // NewSettlementListQuery creates settlement list query with default values. 83 func NewSettlementListQuery() SettlementListQuery { 84 return SettlementListQuery{ 85 PaginationQuery: NewPaginationQuery(), 86 } 87 } 88 89 // SettlementListQuery allows to filter requested settlements. 90 // swagger:parameters settlementList 91 type SettlementListQuery struct { 92 PaginationQuery 93 94 // Filter the settlements from this date. Formatted in RFC3339 e.g. 2020-07-01. 95 // in: query 96 DateFrom *strfmt.Date `json:"date_from"` 97 98 // Filter the settlements until this date Formatted in RFC3339 e.g. 2020-07-30. 99 // in: query 100 DateTo *strfmt.Date `json:"date_to"` 101 102 // Provider identity to filter the sessions by. 103 // in: query 104 ProviderID *string `json:"provider_id"` 105 106 // Hermes ID to filter the sessions by. 107 // in: query 108 HermesID *string `json:"hermes_id"` 109 110 // Settlement type to filter the sessions by. "settlement" or "withdrawal" 111 // in: query 112 Types []string `json:"types"` 113 } 114 115 // Bind creates and validates query from API request. 116 func (q *SettlementListQuery) Bind(request *http.Request) *apierror.APIError { 117 v := apierror.NewValidator() 118 if err := q.PaginationQuery.Bind(request); err != nil { 119 for field, fieldErr := range err.Err.Fields { 120 v.Fail(field, fieldErr.Code, fieldErr.Message) 121 } 122 } 123 124 qs := request.URL.Query() 125 if qStr := qs.Get("date_from"); qStr != "" { 126 if qVal, err := parseDate(qStr); err != nil { 127 v.Invalid("date_from", "Could not parse 'date_from'") 128 } else { 129 q.DateFrom = qVal 130 } 131 } 132 if qStr := qs.Get("date_to"); qStr != "" { 133 if qVal, err := parseDate(qStr); err != nil { 134 v.Invalid("date_to", "Could not parse 'date_to'") 135 } else { 136 q.DateTo = qVal 137 } 138 } 139 if qStr := qs.Get("provider_id"); qStr != "" { 140 q.ProviderID = &qStr 141 } 142 if qStr := qs.Get("hermes_id"); qStr != "" { 143 q.HermesID = &qStr 144 } 145 146 if types, ok := qs["types"]; ok { 147 q.Types = append(q.Types, types...) 148 } 149 150 return v.Err() 151 } 152 153 // ToFilter converts API query to storage filter. 154 func (q *SettlementListQuery) ToFilter() pingpong.SettlementHistoryFilter { 155 filter := pingpong.SettlementHistoryFilter{} 156 if q.DateFrom != nil { 157 timeFrom := time.Time(*q.DateFrom).Truncate(24 * time.Hour) 158 filter.TimeFrom = &timeFrom 159 } 160 if q.DateTo != nil { 161 timeTo := time.Time(*q.DateTo).Truncate(24 * time.Hour).Add(23 * time.Hour).Add(59 * time.Minute).Add(59 * time.Second) 162 filter.TimeTo = &timeTo 163 } 164 if q.ProviderID != nil { 165 providerID := identity.FromAddress(*q.ProviderID) 166 filter.ProviderID = &providerID 167 } 168 if q.HermesID != nil { 169 hermesID := common.HexToAddress(*q.HermesID) 170 filter.HermesID = &hermesID 171 } 172 if q.Types != nil { 173 for _, qt := range q.Types { 174 filter.Types = append(filter.Types, pingpong.HistoryType(qt)) 175 } 176 } 177 return filter 178 } 179 180 // NewSettlementListResponse maps to API settlement list. 181 func NewSettlementListResponse( 182 WithdrawalTotal *big.Int, 183 settlements []pingpong.SettlementHistoryEntry, 184 paginator *utils.Paginator, 185 ) SettlementListResponse { 186 dtoArray := make([]SettlementDTO, len(settlements)) 187 for i, settlement := range settlements { 188 dtoArray[i] = NewSettlementDTO(settlement) 189 } 190 191 return SettlementListResponse{ 192 Items: dtoArray, 193 PageableDTO: NewPageableDTO(paginator), 194 WithdrawalTotal: WithdrawalTotal.String(), 195 } 196 } 197 198 // SettlementListResponse defines settlement list representable as json. 199 // swagger:model SettlementListResponse 200 type SettlementListResponse struct { 201 Items []SettlementDTO `json:"items"` 202 WithdrawalTotal string `json:"withdrawal_total"` 203 PageableDTO 204 } 205 206 // NewSettlementDTO maps to API settlement. 207 func NewSettlementDTO(settlement pingpong.SettlementHistoryEntry) SettlementDTO { 208 return SettlementDTO{ 209 TxHash: settlement.TxHash.Hex(), 210 ProviderID: settlement.ProviderID.Address, 211 HermesID: settlement.HermesID.Hex(), 212 ChannelAddress: settlement.ChannelAddress.Hex(), 213 Beneficiary: settlement.Beneficiary.Hex(), 214 Amount: settlement.Amount, 215 SettledAt: settlement.Time.Format(time.RFC3339), 216 Fees: settlement.Fees, 217 Error: settlement.Error, 218 IsWithdrawal: settlement.IsWithdrawal, 219 BlockExplorerURL: settlement.BlockExplorerURL, 220 } 221 } 222 223 // SettlementDTO represents the settlement object. 224 // swagger:model SettlementDTO 225 type SettlementDTO struct { 226 // example: 0x20c070a9be65355adbd2ba479e095e2e8ed7e692596548734984eab75d3fdfa5 227 TxHash string `json:"tx_hash"` 228 229 // example: 0x0000000000000000000000000000000000000001 230 ProviderID string `json:"provider_id"` 231 232 // example: 0x0000000000000000000000000000000000000001 233 HermesID string `json:"hermes_id"` 234 235 // example: 0x0000000000000000000000000000000000000001 236 ChannelAddress string `json:"channel_address"` 237 238 // example: 0x0000000000000000000000000000000000000001 239 Beneficiary string `json:"beneficiary"` 240 241 // example: 500000 242 Amount *big.Int `json:"amount"` 243 244 // example: 2019-06-06T11:04:43.910035Z 245 SettledAt string `json:"settled_at"` 246 247 // example: 500000 248 Fees *big.Int `json:"fees"` 249 250 // example: false 251 IsWithdrawal bool `json:"is_withdrawal"` 252 253 // example: https://example.com 254 BlockExplorerURL string `json:"block_explorer_url"` 255 256 // example: internal server error 257 Error string `json:"error"` 258 } 259 260 // SettleRequest represents the request to settle hermes promises 261 // swagger:model SettleRequestDTO 262 type SettleRequest struct { 263 HermesIDs []common.Address `json:"hermes_ids"` 264 ProviderID string `json:"provider_id"` 265 266 // Deprecated 267 HermesID string `json:"hermes_id"` 268 } 269 270 // WithdrawRequest represents the request to withdraw earnings to l1. 271 // swagger:model WithdrawRequestDTO 272 type WithdrawRequest struct { 273 HermesID string `json:"hermes_id"` 274 ProviderID string `json:"provider_id"` 275 Beneficiary string `json:"beneficiary"` 276 FromChainID int64 `json:"from_chain_id"` 277 ToChainID int64 `json:"to_chain_id"` 278 Amount string `json:"amount,omitempty"` 279 } 280 281 // Validate will validate a given request 282 func (w *WithdrawRequest) Validate() *apierror.APIError { 283 v := apierror.NewValidator() 284 zeroAddr := common.HexToAddress("").Hex() 285 if !common.IsHexAddress(w.HermesID) || w.HermesID == zeroAddr { 286 v.Invalid("hermes_id", "'hermes_id' should be a valid hex address") 287 } 288 if !common.IsHexAddress(w.ProviderID) || w.ProviderID == zeroAddr { 289 v.Invalid("provider_id", "'provider_id' should be a valid hex address") 290 } 291 if !common.IsHexAddress(w.Beneficiary) || w.Beneficiary == zeroAddr { 292 v.Invalid("beneficiary", "'beneficiary' should be a valid hex address") 293 } 294 295 amount, err := w.AmountInMYST() 296 if err != nil { 297 v.Invalid("amount", err.Error()) 298 } else if amount != nil && amount.Cmp(crypto.FloatToBigMyst(99)) > 0 { 299 v.Invalid("amount", "withdrawal amount cannot be more than 99 MYST") 300 } 301 302 return v.Err() 303 } 304 305 // AmountInMYST will return the amount value converted to big.Int MYST. 306 // 307 // Amount can be `nil` 308 func (w *WithdrawRequest) AmountInMYST() (*big.Int, error) { 309 if w.Amount == "" { 310 return nil, nil 311 } 312 313 res, ok := big.NewInt(0).SetString(w.Amount, 10) 314 if !ok { 315 return nil, fmt.Errorf("%v is not a valid integer", w.Amount) 316 } 317 318 return res, nil 319 } 320 321 // SettleWithBeneficiaryRequest represent the request to settle with new beneficiary address. 322 type SettleWithBeneficiaryRequest struct { 323 ProviderID string `json:"provider_id"` 324 HermesID string `json:"hermes_id"` 325 Beneficiary string `json:"beneficiary"` 326 } 327 328 // DecreaseStakeRequest represents the decrease stake request 329 // swagger:model DecreaseStakeRequest 330 type DecreaseStakeRequest struct { 331 ID string `json:"id,omitempty"` 332 Amount *big.Int `json:"amount,omitempty"` 333 } 334 335 // ReferralTokenResponse represents a response for referral token. 336 // swagger:model ReferralTokenResponse 337 type ReferralTokenResponse struct { 338 Token string `json:"token"` 339 } 340 341 // BeneficiaryTxStatus settle with beneficiary transaction status. 342 // swagger:model BeneficiaryTxStatus 343 type BeneficiaryTxStatus struct { 344 State beneficiary.SettleState `json:"state"` 345 Error string `json:"error"` 346 // example: 0x0000000000000000000000000000000000000001 347 ChangeTo string `json:"change_to"` 348 } 349 350 // TokenRewardAmount represents a response for token rewards. 351 // swagger:model TokenRewardAmount 352 type TokenRewardAmount struct { 353 Amount *big.Int `json:"amount"` 354 } 355 356 // ChainSummary represents a response for token rewards. 357 // swagger:model ChainSummary 358 type ChainSummary struct { 359 Chains map[int64]string `json:"chains"` 360 CurrentChain int64 `json:"current_chain"` 361 }