github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/tequilapi/endpoints/transactor_test.go (about) 1 /* 2 * Copyright (C) 2019 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 endpoints 19 20 import ( 21 "bytes" 22 "encoding/json" 23 "errors" 24 "fmt" 25 "math/big" 26 "net/http" 27 "net/http/httptest" 28 "testing" 29 "time" 30 31 "github.com/mysteriumnetwork/go-rest/apierror" 32 33 "github.com/mysteriumnetwork/node/config" 34 35 "github.com/mysteriumnetwork/node/tequilapi/contract" 36 37 "github.com/ethereum/go-ethereum/common" 38 "github.com/stretchr/testify/assert" 39 40 "github.com/mysteriumnetwork/node/mocks" 41 "github.com/mysteriumnetwork/node/requests" 42 "github.com/mysteriumnetwork/node/session/pingpong" 43 44 "github.com/mysteriumnetwork/node/identity" 45 "github.com/mysteriumnetwork/node/identity/registry" 46 ) 47 48 var identityRegData = `{ 49 "beneficiary": "0xbe180c8CA53F280C7BE8669596fF7939d933AA10", 50 "fee": 1, 51 "stake": 0 52 }` 53 54 func Test_RegisterIdentity(t *testing.T) { 55 mockResponse := `{ "fee": 1 }` 56 server := newTestTransactorServer(http.StatusAccepted, mockResponse) 57 58 router := summonTestGin() 59 60 tr := registry.NewTransactor(requests.NewHTTPClient(server.URL, requests.DefaultTimeout), server.URL, &mockAddressProvider{}, fakeSignerFactory, mocks.NewEventBus(), nil, time.Minute) 61 a := registry.NewAffiliator(requests.NewHTTPClient(server.URL, requests.DefaultTimeout), server.URL) 62 err := AddRoutesForTransactor(®istry.FakeRegistry{RegistrationStatus: registry.Unregistered}, tr, a, nil, &settlementHistoryProviderMock{}, &mockAddressProvider{}, nil, nil, &mockPilvytis{})(router) 63 assert.NoError(t, err) 64 65 req, err := http.NewRequest( 66 http.MethodPost, 67 "/identities/0x0000000000000000000000000000000000000000/register", 68 bytes.NewBufferString(identityRegData), 69 ) 70 assert.Nil(t, err) 71 72 resp := httptest.NewRecorder() 73 router.ServeHTTP(resp, req) 74 75 assert.Equal(t, http.StatusAccepted, resp.Code) 76 assert.Equal(t, "", resp.Body.String()) 77 } 78 79 func Test_Get_TransactorFees(t *testing.T) { 80 mockResponse := `{ "fee": 1000000000000000000 }` 81 server := newTestTransactorServer(http.StatusOK, mockResponse) 82 83 router := summonTestGin() 84 85 tr := registry.NewTransactor(requests.NewHTTPClient(server.URL, requests.DefaultTimeout), server.URL, &mockAddressProvider{}, fakeSignerFactory, mocks.NewEventBus(), nil, time.Minute) 86 a := registry.NewAffiliator(requests.NewHTTPClient(server.URL, requests.DefaultTimeout), server.URL) 87 err := AddRoutesForTransactor(mockIdentityRegistryInstance, tr, a, &mockSettler{ 88 feeToReturn: 11_000, 89 }, &settlementHistoryProviderMock{}, &mockAddressProvider{}, nil, nil, nil)(router) 90 assert.NoError(t, err) 91 92 req, err := http.NewRequest( 93 http.MethodGet, 94 "/transactor/fees", 95 nil, 96 ) 97 assert.Nil(t, err) 98 99 resp := httptest.NewRecorder() 100 router.ServeHTTP(resp, req) 101 102 assert.Equal(t, http.StatusOK, resp.Code) 103 assert.JSONEq(t, 104 `{ 105 "registration": 1000000000000000000, 106 "registration_tokens": { 107 "ether": "1", 108 "human": "1", 109 "wei": "1000000000000000000" 110 }, 111 "settlement": 1000000000000000000, 112 "settlement_tokens": { 113 "ether": "1", 114 "human": "1", 115 "wei": "1000000000000000000" 116 }, 117 "hermes": 11000, 118 "hermes_percent": "1.1000", 119 "decreaseStake": 1000000000000000000, 120 "decrease_stake_tokens": { 121 "ether": "1", 122 "human": "1", 123 "wei": "1000000000000000000" 124 } 125 } 126 `, 127 resp.Body.String()) 128 } 129 130 func Test_SettleAsync_OK(t *testing.T) { 131 mockResponse := "" 132 server := newTestTransactorServer(http.StatusAccepted, mockResponse) 133 134 router := summonTestGin() 135 136 tr := registry.NewTransactor(requests.NewHTTPClient(server.URL, requests.DefaultTimeout), server.URL, &mockAddressProvider{}, fakeSignerFactory, mocks.NewEventBus(), nil, time.Minute) 137 a := registry.NewAffiliator(requests.NewHTTPClient(server.URL, requests.DefaultTimeout), server.URL) 138 err := AddRoutesForTransactor(mockIdentityRegistryInstance, tr, a, &mockSettler{}, &settlementHistoryProviderMock{}, &mockAddressProvider{}, &mockBeneficiaryProvider{ 139 b: common.HexToAddress("0x0000000000000000000000000000000000000001"), 140 }, nil, nil)(router) 141 assert.NoError(t, err) 142 143 settleRequest := `{"hermes_id": "0xbe180c8CA53F280C7BE8669596fF7939d933AA10", "provider_id": "0xbe180c8CA53F280C7BE8669596fF7939d933AA10"}` 144 req, err := http.NewRequest( 145 http.MethodPost, 146 "/transactor/settle/async", 147 bytes.NewBufferString(settleRequest), 148 ) 149 assert.Nil(t, err) 150 151 resp := httptest.NewRecorder() 152 router.ServeHTTP(resp, req) 153 154 assert.Equal(t, http.StatusAccepted, resp.Code) 155 assert.Equal(t, "", resp.Body.String()) 156 } 157 158 func Test_SettleAsync_ReturnsError(t *testing.T) { 159 mockResponse := "" 160 server := newTestTransactorServer(http.StatusAccepted, mockResponse) 161 162 router := summonTestGin() 163 164 tr := registry.NewTransactor(requests.NewHTTPClient(server.URL, requests.DefaultTimeout), server.URL, &mockAddressProvider{}, fakeSignerFactory, mocks.NewEventBus(), nil, time.Minute) 165 a := registry.NewAffiliator(requests.NewHTTPClient(server.URL, requests.DefaultTimeout), server.URL) 166 err := AddRoutesForTransactor(mockIdentityRegistryInstance, tr, a, &mockSettler{errToReturn: errors.New("explosions everywhere")}, &settlementHistoryProviderMock{}, &mockAddressProvider{}, nil, nil, nil)(router) 167 assert.NoError(t, err) 168 169 settleRequest := `asdasdasd` 170 req, err := http.NewRequest( 171 http.MethodPost, 172 "/transactor/settle/async", 173 bytes.NewBufferString(settleRequest), 174 ) 175 assert.Nil(t, err) 176 177 resp := httptest.NewRecorder() 178 router.ServeHTTP(resp, req) 179 180 assert.Equal(t, http.StatusInternalServerError, resp.Code) 181 assert.Equal(t, "err_hermes_settle_async", apierror.Parse(resp.Result()).Err.Code) 182 } 183 184 func Test_SettleSync_OK(t *testing.T) { 185 mockResponse := "" 186 server := newTestTransactorServer(http.StatusAccepted, mockResponse) 187 188 router := summonTestGin() 189 190 tr := registry.NewTransactor(requests.NewHTTPClient(server.URL, requests.DefaultTimeout), server.URL, &mockAddressProvider{}, fakeSignerFactory, mocks.NewEventBus(), nil, time.Minute) 191 a := registry.NewAffiliator(requests.NewHTTPClient(server.URL, requests.DefaultTimeout), server.URL) 192 err := AddRoutesForTransactor(mockIdentityRegistryInstance, tr, a, &mockSettler{}, &settlementHistoryProviderMock{}, &mockAddressProvider{}, nil, nil, nil)(router) 193 assert.NoError(t, err) 194 195 settleRequest := `{"hermes_id": "0xbe180c8CA53F280C7BE8669596fF7939d933AA10", "provider_id": "0xbe180c8CA53F280C7BE8669596fF7939d933AA10"}` 196 req, err := http.NewRequest( 197 http.MethodPost, 198 "/transactor/settle/sync", 199 bytes.NewBufferString(settleRequest), 200 ) 201 assert.Nil(t, err) 202 203 resp := httptest.NewRecorder() 204 router.ServeHTTP(resp, req) 205 206 assert.Equal(t, http.StatusOK, resp.Code) 207 assert.Equal(t, "", resp.Body.String()) 208 } 209 210 func Test_SettleSync_ReturnsError(t *testing.T) { 211 mockResponse := "" 212 server := newTestTransactorServer(http.StatusAccepted, mockResponse) 213 214 router := summonTestGin() 215 216 tr := registry.NewTransactor(requests.NewHTTPClient(server.URL, requests.DefaultTimeout), server.URL, &mockAddressProvider{}, fakeSignerFactory, mocks.NewEventBus(), nil, time.Minute) 217 a := registry.NewAffiliator(requests.NewHTTPClient(server.URL, requests.DefaultTimeout), server.URL) 218 err := AddRoutesForTransactor(mockIdentityRegistryInstance, tr, a, &mockSettler{errToReturn: errors.New("explosions everywhere")}, &settlementHistoryProviderMock{}, &mockAddressProvider{}, nil, nil, nil)(router) 219 assert.NoError(t, err) 220 221 settleRequest := `{"hermes_id": "0xbe180c8CA53F280C7BE8669596fF7939d933AA10", "provider_id": "0xbe180c8CA53F280C7BE8669596fF7939d933AA10"}` 222 req, err := http.NewRequest( 223 http.MethodPost, 224 "/transactor/settle/sync", 225 bytes.NewBufferString(settleRequest), 226 ) 227 assert.Nil(t, err) 228 229 resp := httptest.NewRecorder() 230 router.ServeHTTP(resp, req) 231 232 assert.Equal(t, http.StatusInternalServerError, resp.Code) 233 assert.Equal(t, "err_hermes_settle", apierror.Parse(resp.Result()).Err.Code) 234 } 235 236 func Test_SettleHistory(t *testing.T) { 237 t.Run("returns error on failed history retrieval", func(t *testing.T) { 238 mockResponse := "" 239 server := newTestTransactorServer(http.StatusAccepted, mockResponse) 240 defer server.Close() 241 242 router := summonTestGin() 243 tr := registry.NewTransactor(requests.NewHTTPClient(server.URL, requests.DefaultTimeout), server.URL, &mockAddressProvider{}, fakeSignerFactory, mocks.NewEventBus(), nil, time.Minute) 244 a := registry.NewAffiliator(requests.NewHTTPClient(server.URL, requests.DefaultTimeout), server.URL) 245 err := AddRoutesForTransactor(mockIdentityRegistryInstance, tr, a, nil, &settlementHistoryProviderMock{errToReturn: errors.New("explosions everywhere")}, &mockAddressProvider{}, nil, nil, nil)(router) 246 assert.NoError(t, err) 247 248 req, err := http.NewRequest(http.MethodGet, "/transactor/settle/history", nil) 249 assert.Nil(t, err) 250 251 resp := httptest.NewRecorder() 252 router.ServeHTTP(resp, req) 253 254 assert.Equal(t, http.StatusInternalServerError, resp.Code) 255 assert.Equal(t, "err_transactor_settle_history", apierror.Parse(resp.Result()).Err.Code) 256 }) 257 t.Run("returns settlement history", func(t *testing.T) { 258 mockStorage := &settlementHistoryProviderMock{settlementHistoryToReturn: []pingpong.SettlementHistoryEntry{ 259 { 260 TxHash: common.HexToHash("0x88af51047ff2da1e3626722fe239f70c3ddd668f067b2ac8d67b280d2eff39f7"), 261 Time: time.Date(2020, 1, 2, 3, 4, 5, 0, time.UTC), 262 Beneficiary: common.HexToAddress("0x4443189b9b945DD38E7bfB6167F9909451582eE5"), 263 Amount: big.NewInt(123), 264 Fees: big.NewInt(20), 265 IsWithdrawal: true, 266 }, 267 { 268 TxHash: common.HexToHash("0x9eea5c4da8a67929d5dd5d8b6dedb3bd44e7bd3ec299f8972f3212db8afb938a"), 269 Time: time.Date(2020, 6, 7, 8, 9, 10, 0, time.UTC), 270 Amount: big.NewInt(456), 271 Fees: big.NewInt(50), 272 IsWithdrawal: true, 273 }, 274 }} 275 276 server := newTestTransactorServer(http.StatusAccepted, "") 277 defer server.Close() 278 279 router := summonTestGin() 280 tr := registry.NewTransactor(requests.NewHTTPClient(server.URL, requests.DefaultTimeout), server.URL, &mockAddressProvider{}, fakeSignerFactory, mocks.NewEventBus(), nil, time.Minute) 281 a := registry.NewAffiliator(requests.NewHTTPClient(server.URL, requests.DefaultTimeout), server.URL) 282 err := AddRoutesForTransactor(mockIdentityRegistryInstance, tr, a, nil, mockStorage, &mockAddressProvider{}, nil, nil, nil)(router) 283 assert.NoError(t, err) 284 285 req, err := http.NewRequest(http.MethodGet, "/transactor/settle/history", nil) 286 assert.Nil(t, err) 287 288 resp := httptest.NewRecorder() 289 router.ServeHTTP(resp, req) 290 291 assert.Equal(t, http.StatusOK, resp.Code) 292 assert.JSONEq( 293 t, 294 `{ 295 "items": [ 296 { 297 "tx_hash": "0x88af51047ff2da1e3626722fe239f70c3ddd668f067b2ac8d67b280d2eff39f7", 298 "provider_id": "", 299 "hermes_id": "0x0000000000000000000000000000000000000000", 300 "channel_address": "0x0000000000000000000000000000000000000000", 301 "beneficiary":"0x4443189b9B945dD38e7bfB6167F9909451582EE5", 302 "amount": 123, 303 "settled_at": "2020-01-02T03:04:05Z", 304 "fees": 20, 305 "is_withdrawal": true, 306 "block_explorer_url": "", 307 "error": "" 308 }, 309 { 310 "tx_hash": "0x9eea5c4da8a67929d5dd5d8b6dedb3bd44e7bd3ec299f8972f3212db8afb938a", 311 "provider_id": "", 312 "hermes_id": "0x0000000000000000000000000000000000000000", 313 "channel_address": "0x0000000000000000000000000000000000000000", 314 "beneficiary": "0x0000000000000000000000000000000000000000", 315 "amount": 456, 316 "settled_at": "2020-06-07T08:09:10Z", 317 "fees": 50, 318 "is_withdrawal": true, 319 "block_explorer_url": "", 320 "error": "" 321 } 322 ], 323 "withdrawal_total": "579", 324 "page": 1, 325 "page_size": 50, 326 "total_items": 2, 327 "total_pages": 1 328 }`, 329 resp.Body.String(), 330 ) 331 }) 332 t.Run("respects filters", func(t *testing.T) { 333 mockStorage := &settlementHistoryProviderMock{} 334 335 server := newTestTransactorServer(http.StatusAccepted, "") 336 defer server.Close() 337 router := summonTestGin() 338 tr := registry.NewTransactor(requests.NewHTTPClient(server.URL, requests.DefaultTimeout), server.URL, &mockAddressProvider{}, fakeSignerFactory, mocks.NewEventBus(), nil, time.Minute) 339 a := registry.NewAffiliator(requests.NewHTTPClient(server.URL, requests.DefaultTimeout), server.URL) 340 err := AddRoutesForTransactor(mockIdentityRegistryInstance, tr, a, nil, mockStorage, &mockAddressProvider{}, nil, nil, nil)(router) 341 assert.NoError(t, err) 342 343 req, err := http.NewRequest( 344 http.MethodGet, 345 "/transactor/settle/history?date_from=2020-09-19&date_to=2020-09-20&provider_id=0xab1&hermes_id=0xaB2&types=settlement&types=withdrawal", 346 nil, 347 ) 348 assert.Nil(t, err) 349 350 resp := httptest.NewRecorder() 351 router.ServeHTTP(resp, req) 352 353 expectedTimeFrom := time.Date(2020, 9, 19, 0, 0, 0, 0, time.UTC) 354 expectedTimeTo := time.Date(2020, 9, 20, 23, 59, 59, 0, time.UTC) 355 expectedProviderID := identity.FromAddress("0xab1") 356 expectedHermesID := common.HexToAddress("0xaB2") 357 expectedTypes := []pingpong.HistoryType{pingpong.SettlementType, pingpong.WithdrawalType} 358 assert.Equal( 359 t, 360 &pingpong.SettlementHistoryFilter{ 361 TimeFrom: &expectedTimeFrom, 362 TimeTo: &expectedTimeTo, 363 ProviderID: &expectedProviderID, 364 HermesID: &expectedHermesID, 365 Types: expectedTypes, 366 }, 367 mockStorage.calledWithFilter, 368 ) 369 }) 370 } 371 372 func Test_AvailableChains(t *testing.T) { 373 // given 374 router := summonTestGin() 375 err := AddRoutesForTransactor(nil, nil, nil, nil, nil, nil, nil, nil, nil)(router) 376 assert.NoError(t, err) 377 config.Current.SetUser(config.FlagChainID.Name, config.FlagChainID.Value) 378 379 // when 380 req, err := http.NewRequest( 381 http.MethodGet, 382 "/transactor/chain-summary", 383 nil, 384 ) 385 resp := httptest.NewRecorder() 386 router.ServeHTTP(resp, req) 387 388 // then 389 var chainSummary contract.ChainSummary 390 err = json.NewDecoder(resp.Body).Decode(&chainSummary) 391 fmt.Println(chainSummary) 392 assert.NoError(t, err) 393 assert.Equal(t, "Polygon Mainnet", chainSummary.Chains[137]) 394 assert.Equal(t, config.FlagChainID.Value, chainSummary.CurrentChain) 395 } 396 397 func Test_Withdrawal(t *testing.T) { 398 // given 399 router := summonTestGin() 400 401 settler := &mockSettler{ 402 feeToReturn: 11, 403 } 404 err := AddRoutesForTransactor(nil, nil, nil, settler, nil, nil, nil, nil, nil)(router) 405 assert.NoError(t, err) 406 407 config.Current.SetUser(config.FlagChainID.Name, config.FlagChainID.Value) 408 // expect 409 for _, data := range []struct { 410 fromChainID int64 411 toChainID int64 412 expectedToChainID int64 413 expectedFromChainID int64 414 }{ 415 {fromChainID: 1, toChainID: config.FlagChainID.Value, expectedFromChainID: 1, expectedToChainID: config.FlagChainID.Value}, 416 {fromChainID: 0, toChainID: 0, expectedFromChainID: config.FlagChainID.Value, expectedToChainID: 0}, 417 {fromChainID: 1, toChainID: 0, expectedFromChainID: 1, expectedToChainID: 0}, 418 } { 419 t.Run(fmt.Sprintf("succeed withdrawal with fromChainID: %d, toChainID: %d", data.fromChainID, data.toChainID), func(t *testing.T) { 420 // when 421 body, err := json.Marshal(contract.WithdrawRequest{ 422 HermesID: "0xe948dae2ce1faf719ba1091d8c6664a46bab073d", 423 ProviderID: "0xe948dae2ce1faf719ba1091d8c6664a46bab073d", 424 Beneficiary: "0xe948dae2ce1faf719ba1091d8c6664a46bab073d", 425 ToChainID: data.toChainID, 426 FromChainID: data.fromChainID, 427 }) 428 assert.NoError(t, err) 429 req, err := http.NewRequest( 430 http.MethodPost, 431 "/transactor/settle/withdraw", 432 bytes.NewBuffer(body), 433 ) 434 assert.NoError(t, err) 435 resp := httptest.NewRecorder() 436 router.ServeHTTP(resp, req) 437 438 // then 439 assert.Equal(t, http.StatusOK, resp.Code) 440 assert.Equal(t, data.expectedToChainID, settler.capturedToChainID) 441 assert.Equal(t, data.expectedFromChainID, settler.capturedFromChainID) 442 }) 443 } 444 445 // expect 446 for _, data := range []struct { 447 fromChainID int64 448 toChainID int64 449 }{ 450 {fromChainID: -1, toChainID: 0}, 451 {fromChainID: 0, toChainID: -1}, 452 {fromChainID: -1, toChainID: -1}, 453 } { 454 t.Run(fmt.Sprintf("fail withdrawal with unsuported fromChainID: %d, toChainID: %d", data.fromChainID, data.toChainID), func(t *testing.T) { 455 // when 456 body, err := json.Marshal(contract.WithdrawRequest{ 457 HermesID: "0xe948dae2ce1faf719ba1091d8c6664a46bab073d", 458 ProviderID: "0xe948dae2ce1faf719ba1091d8c6664a46bab073d", 459 Beneficiary: "0xe948dae2ce1faf719ba1091d8c6664a46bab073d", 460 ToChainID: data.toChainID, 461 FromChainID: data.fromChainID, 462 }) 463 assert.NoError(t, err) 464 req, err := http.NewRequest( 465 http.MethodPost, 466 "/transactor/settle/withdraw", 467 bytes.NewBuffer(body), 468 ) 469 assert.NoError(t, err) 470 resp := httptest.NewRecorder() 471 router.ServeHTTP(resp, req) 472 473 // then 474 assert.Equal(t, http.StatusBadRequest, resp.Code) 475 }) 476 } 477 } 478 479 func newTestTransactorServer(mockStatus int, mockResponse string) *httptest.Server { 480 return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 481 w.WriteHeader(mockStatus) 482 w.Write([]byte(mockResponse)) 483 })) 484 } 485 486 var fakeSignerFactory = func(id identity.Identity) identity.Signer { 487 return &fakeSigner{} 488 } 489 490 type fakeSigner struct { 491 } 492 493 func pad(b []byte, size int) []byte { 494 if len(b) >= size { 495 return b 496 } 497 tmp := make([]byte, size) 498 copy(tmp[size-len(b):], b) 499 return tmp 500 } 501 502 func (fs *fakeSigner) Sign(message []byte) (identity.Signature, error) { 503 b := make([]byte, 65) 504 b = pad(b, 65) 505 return identity.SignatureBytes(b), nil 506 } 507 508 type mockSettler struct { 509 errToReturn error 510 511 feeToReturn uint16 512 feeErrorToReturn error 513 514 capturedToChainID int64 515 capturedFromChainID int64 516 } 517 518 func (ms *mockSettler) ForceSettle(_ int64, _ identity.Identity, _ ...common.Address) error { 519 return ms.errToReturn 520 } 521 522 func (ms *mockSettler) ForceSettleAsync(_ int64, _ identity.Identity, _ ...common.Address) error { 523 return ms.errToReturn 524 } 525 526 func (ms *mockSettler) SettleIntoStake(_ int64, providerID identity.Identity, hermesID ...common.Address) error { 527 return nil 528 } 529 530 func (ms *mockSettler) GetHermesFee(_ int64, _ common.Address) (uint16, error) { 531 return ms.feeToReturn, ms.feeErrorToReturn 532 } 533 534 func (ms *mockSettler) Withdraw(fromChainID int64, toChainID int64, providerID identity.Identity, hermesID, beneficiary common.Address, amount *big.Int) error { 535 ms.capturedToChainID = toChainID 536 ms.capturedFromChainID = fromChainID 537 return nil 538 } 539 540 type settlementHistoryProviderMock struct { 541 settlementHistoryToReturn []pingpong.SettlementHistoryEntry 542 errToReturn error 543 544 calledWithFilter *pingpong.SettlementHistoryFilter 545 } 546 547 func (shpm *settlementHistoryProviderMock) List(filter pingpong.SettlementHistoryFilter) ([]pingpong.SettlementHistoryEntry, error) { 548 shpm.calledWithFilter = &filter 549 return shpm.settlementHistoryToReturn, shpm.errToReturn 550 }