@@ -9,33 +9,43 @@ export default Engine =>
9
9
if ( ! this . isNewTradeOption ( tradeOption ) ) {
10
10
return ;
11
11
}
12
+
13
+ // Generate a purchase reference when trade options are different from previous trade options.
14
+ // This will ensure the bot doesn't mistakenly purchase the wrong proposal.
15
+ this . regeneratePurchaseReference ( ) ;
12
16
this . tradeOption = tradeOption ;
13
- this . proposalTemplates = tradeOptionToProposal ( tradeOption ) ;
17
+ this . proposalTemplates = tradeOptionToProposal ( tradeOption , this . getPurchaseReference ( ) ) ;
14
18
this . renewProposalsOnPurchase ( ) ;
15
19
}
16
20
selectProposal ( contractType ) {
17
- let toBuy ;
21
+ const { proposals } = this . data ;
18
22
19
- if ( ! this . data . has ( ' proposals' ) ) {
23
+ if ( proposals . length === 0 ) {
20
24
throw Error ( translate ( 'Proposals are not ready' ) ) ;
21
25
}
22
26
23
- this . data . get ( 'proposals' ) . forEach ( proposal => {
24
- if ( proposal . contractType === contractType ) {
27
+ const toBuy = proposals . find ( proposal => {
28
+ if (
29
+ proposal . contractType === contractType &&
30
+ proposal . purchaseReference === this . getPurchaseReference ( )
31
+ ) {
25
32
if ( proposal . error ) {
26
- const { error } = proposal . error ;
27
- throw new TrackJSError ( error . error . code , error . error . message , error ) ;
28
- } else {
29
- toBuy = proposal ;
33
+ const { error } = proposal . error . error ;
34
+ const { code, message } = error ;
35
+ throw new TrackJSError ( code , message , error ) ;
30
36
}
37
+
38
+ return proposal ;
31
39
}
40
+
41
+ return false ;
32
42
} ) ;
33
43
34
44
if ( ! toBuy ) {
35
45
throw new TrackJSError (
36
46
'CustomInvalidProposal' ,
37
47
translate ( 'Selected proposal does not exist' ) ,
38
- Array . from ( this . data . get ( ' proposals' ) ) . map ( proposal => proposal [ 1 ] )
48
+ this . data . proposals
39
49
) ;
40
50
}
41
51
@@ -48,93 +58,73 @@ export default Engine =>
48
58
this . unsubscribeProposals ( ) . then ( ( ) => this . requestProposals ( ) ) ;
49
59
}
50
60
clearProposals ( ) {
51
- this . data = this . data . set ( ' proposals' , new Map ( ) ) ;
61
+ this . data . proposals = [ ] ;
52
62
this . store . dispatch ( clearProposals ( ) ) ;
53
63
}
54
64
requestProposals ( ) {
55
65
Promise . all (
56
66
this . proposalTemplates . map ( proposal =>
57
- doUntilDone ( ( ) =>
58
- this . api . subscribeToPriceForContractProposal ( proposal ) . catch ( e => {
59
- if ( e && e . name === 'RateLimit' ) {
60
- throw e ;
61
- }
62
-
63
- const errorCode = e . error && e . error . error && e . error . error . code ;
64
-
65
- if ( errorCode === 'ContractBuyValidationError' ) {
66
- const { uuid } = e . error . echo_req . passthrough ;
67
-
68
- if ( ! this . data . hasIn ( [ 'forgetProposals' , uuid ] ) ) {
69
- // Add to proposals map with error. Will later be shown to user, see selectProposal.
70
- this . data = this . data . setIn ( [ 'proposals' , uuid ] , {
71
- ...proposal ,
72
- ...proposal . passthrough ,
73
- error : e ,
74
- } ) ;
75
- }
76
-
77
- return null ;
78
- }
79
-
80
- throw e ;
81
- } )
82
- )
67
+ doUntilDone ( ( ) => this . api . subscribeToPriceForContractProposal ( proposal ) )
83
68
)
84
69
) . catch ( e => this . $scope . observer . emit ( 'Error' , e ) ) ;
85
70
}
86
71
observeProposals ( ) {
87
- this . listen ( 'proposal' , r => {
88
- const { proposal , passthrough } = r ;
89
- const id = passthrough . uuid ;
90
-
91
- if ( ! this . data . hasIn ( [ 'forgetProposals' , id ] ) ) {
92
- this . data = this . data . setIn ( [ 'proposals' , id ] , {
93
- ... proposal ,
94
- ... passthrough ,
95
- } ) ;
72
+ this . listen ( 'proposal' , response => {
73
+ const { passthrough , proposal } = response ;
74
+
75
+ if (
76
+ this . data . proposals . findIndex ( p => p . id === proposal . id ) === - 1 &&
77
+ ! this . data . forgetProposals . includes ( proposal . id )
78
+ ) {
79
+ // Add proposals based on the ID returned by the API.
80
+ this . data . proposals . push ( { ... proposal , ... passthrough } ) ;
96
81
this . checkProposalReady ( ) ;
97
82
}
98
83
} ) ;
99
84
}
100
85
unsubscribeProposals ( ) {
101
- const proposalObj = this . data . get ( 'proposals' ) ;
102
-
103
- if ( ! proposalObj ) {
104
- return Promise . resolve ( ) ;
105
- }
106
-
107
- const proposals = Array . from ( proposalObj . values ( ) ) ;
86
+ const { proposals } = this . data ;
87
+ const removeForgetProposalById = forgetProposalId => {
88
+ this . data . forgetProposals = this . data . forgetProposals . filter ( id => id !== forgetProposalId ) ;
89
+ } ;
108
90
109
91
this . clearProposals ( ) ;
110
92
111
93
return Promise . all (
112
94
proposals . map ( proposal => {
113
- const { uuid : id } = proposal ;
114
- const removeProposal = ( ) => {
115
- this . data = this . data . deleteIn ( [ 'forgetProposals' , id ] ) ;
116
- } ;
117
-
118
- this . data = this . data . setIn ( [ 'forgetProposals' , id ] , true ) ;
95
+ if ( ! this . data . forgetProposals . includes ( proposal . id ) ) {
96
+ this . data . forgetProposals . push ( proposal . id ) ;
97
+ }
119
98
120
99
if ( proposal . error ) {
121
- removeProposal ( ) ;
100
+ removeForgetProposalById ( proposal . id ) ;
122
101
return Promise . resolve ( ) ;
123
102
}
124
103
125
- return doUntilDone ( ( ) => this . api . unsubscribeByID ( proposal . id ) ) . then ( ( ) => removeProposal ( ) ) ;
104
+ return doUntilDone ( ( ) => this . api . unsubscribeByID ( proposal . id ) ) . then ( ( ) =>
105
+ removeForgetProposalById ( proposal . id )
106
+ ) ;
126
107
} )
127
108
) ;
128
109
}
129
110
checkProposalReady ( ) {
130
- const proposals = this . data . get ( 'proposals' ) ;
131
-
132
- if ( proposals && proposals . size === this . proposalTemplates . length ) {
133
- const isSameWithTemplate = this . proposalTemplates . every ( p =>
134
- this . data . hasIn ( [ 'proposals' , p . passthrough . uuid ] )
135
- ) ;
136
-
137
- if ( isSameWithTemplate ) {
111
+ // Proposals are considered ready when the proposals in our memory match the ones
112
+ // we've requested from the API, we determine this by checking the passthrough of the response.
113
+ const { proposals } = this . data ;
114
+
115
+ if ( proposals . length > 0 ) {
116
+ const hasEqualLength = proposals . length === this . proposalTemplates . length ;
117
+ const hasEqualProposals = ( ) =>
118
+ this . proposalTemplates . every (
119
+ template =>
120
+ proposals . findIndex (
121
+ proposal =>
122
+ proposal . purchaseReference === template . passthrough . purchaseReference &&
123
+ proposal . contractType === template . contract_type
124
+ ) !== - 1
125
+ ) ;
126
+
127
+ if ( hasEqualLength && hasEqualProposals ( ) ) {
138
128
this . startPromise . then ( ( ) => this . store . dispatch ( proposalsReady ( ) ) ) ;
139
129
}
140
130
}
@@ -145,16 +135,18 @@ export default Engine =>
145
135
return true ;
146
136
}
147
137
148
- const isNotEqual = key => this . tradeOption [ key ] !== tradeOption [ key ] ;
149
-
150
- return (
151
- isNotEqual ( 'duration' ) ||
152
- isNotEqual ( 'duration_unit' ) ||
153
- isNotEqual ( 'amount' ) ||
154
- isNotEqual ( 'prediction' ) ||
155
- isNotEqual ( 'barrierOffset' ) ||
156
- isNotEqual ( 'secondBarrierOffset' ) ||
157
- isNotEqual ( 'symbol' )
158
- ) ;
138
+ // Compare incoming "tradeOption" argument with "this.tradeOption", if any
139
+ // of the values is different, this is a new tradeOption and new proposals
140
+ // should be generated.
141
+ return [
142
+ 'amount' ,
143
+ 'barrierOffset' ,
144
+ 'basis' ,
145
+ 'duration' ,
146
+ 'duration_unit' ,
147
+ 'prediction' ,
148
+ 'secondBarrierOffset' ,
149
+ 'symbol' ,
150
+ ] . some ( value => this . tradeOption [ value ] !== tradeOption [ value ] ) ;
159
151
}
160
152
} ;
0 commit comments