Skip to main content

nautilus_polymarket/common/
enums.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2026 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16//! Venue-specific enums for the Polymarket CLOB API.
17
18use std::fmt::{Debug, Display};
19
20use nautilus_model::enums::{AggressorSide, OrderSide, OrderStatus, TimeInForce};
21use serde::{Deserialize, Serialize};
22use serde_repr::{Deserialize_repr, Serialize_repr};
23use strum::{Display as StrumDisplay, EnumString};
24use ustr::Ustr;
25
26/// Role of the private key used to sign orders, independent of the wallet signature format.
27#[cfg_attr(
28    feature = "python",
29    pyo3::pyclass(
30        frozen,
31        eq,
32        eq_int,
33        module = "nautilus_trader.adapters.polymarket",
34        from_py_object
35    )
36)]
37#[cfg_attr(
38    feature = "python",
39    pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.adapters.polymarket")
40)]
41#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
42pub enum PolymarketSignerType {
43    #[default]
44    Owner,
45    Session,
46}
47
48#[cfg(feature = "python")]
49#[pyo3::pymethods]
50#[pyo3_stub_gen::derive::gen_stub_pymethods]
51impl PolymarketSignerType {
52    const fn __hash__(&self) -> isize {
53        *self as isize
54    }
55}
56
57/// EIP-712 signature type for order signing.
58///
59/// Serialized as a numeric value (0/1/2/3) on the wire.
60#[cfg_attr(
61    feature = "python",
62    pyo3::pyclass(
63        frozen,
64        eq,
65        eq_int,
66        hash,
67        module = "nautilus_trader.adapters.polymarket",
68        from_py_object,
69    )
70)]
71#[cfg_attr(
72    feature = "python",
73    pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.adapters.polymarket")
74)]
75#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize_repr, Deserialize_repr)]
76#[repr(u8)]
77pub enum PolymarketSignatureType {
78    Eoa = 0,
79    PolyProxy = 1,
80    PolyGnosisSafe = 2,
81    Poly1271 = 3,
82}
83
84/// Outcome label for a Polymarket market token.
85///
86/// Free-form string from the API (e.g. "Yes", "No", "Up", "Down").
87/// Every Polymarket market has exactly two outcome tokens; this holds
88/// whichever label the API assigns to one of them.
89#[repr(C)]
90#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
91pub struct PolymarketOutcome(Ustr);
92
93impl PolymarketOutcome {
94    #[must_use]
95    pub fn yes() -> Self {
96        Self(Ustr::from("Yes"))
97    }
98
99    #[must_use]
100    pub fn no() -> Self {
101        Self(Ustr::from("No"))
102    }
103
104    #[must_use]
105    pub fn up() -> Self {
106        Self(Ustr::from("Up"))
107    }
108
109    #[must_use]
110    pub fn down() -> Self {
111        Self(Ustr::from("Down"))
112    }
113
114    #[must_use]
115    pub const fn inner(&self) -> Ustr {
116        self.0
117    }
118
119    #[must_use]
120    pub fn as_str(&self) -> &str {
121        self.0.as_str()
122    }
123}
124
125impl Debug for PolymarketOutcome {
126    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
127        write!(f, "\"{}\"", self.0)
128    }
129}
130
131impl Display for PolymarketOutcome {
132    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
133        write!(f, "{}", self.0)
134    }
135}
136
137impl From<&str> for PolymarketOutcome {
138    fn from(value: &str) -> Self {
139        Self(Ustr::from(value))
140    }
141}
142
143impl From<Ustr> for PolymarketOutcome {
144    fn from(value: Ustr) -> Self {
145        Self(value)
146    }
147}
148
149/// Order side on the Polymarket CLOB.
150#[derive(
151    Clone, Copy, Debug, PartialEq, Eq, Hash, StrumDisplay, EnumString, Serialize, Deserialize,
152)]
153#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
154#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
155pub enum PolymarketOrderSide {
156    Buy,
157    Sell,
158}
159
160/// Liquidity side for fills.
161#[derive(
162    Clone, Copy, Debug, PartialEq, Eq, Hash, StrumDisplay, EnumString, Serialize, Deserialize,
163)]
164#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
165#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
166pub enum PolymarketLiquiditySide {
167    Maker,
168    Taker,
169}
170
171/// Order type (time-in-force variant) on the Polymarket CLOB.
172#[derive(
173    Clone, Copy, Debug, PartialEq, Eq, Hash, StrumDisplay, EnumString, Serialize, Deserialize,
174)]
175pub enum PolymarketOrderType {
176    FOK,
177    /// Immediate or cancel.
178    FAK,
179    GTC,
180    GTD,
181}
182
183/// WebSocket event type for user channel messages.
184#[derive(
185    Clone, Copy, Debug, PartialEq, Eq, Hash, StrumDisplay, EnumString, Serialize, Deserialize,
186)]
187#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
188#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
189pub enum PolymarketEventType {
190    Placement,
191    /// Emitted for a match.
192    Update,
193    Cancellation,
194    Trade,
195}
196
197/// Order status on the Polymarket CLOB.
198#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, StrumDisplay, EnumString, Serialize)]
199#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
200#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
201pub enum PolymarketOrderStatus {
202    Invalid,
203    Live,
204    /// Marketable but subject to matching delay.
205    Delayed,
206    Matched,
207    /// Marketable but failure delaying, placement not successful.
208    Unmatched,
209    Canceled,
210    CanceledMarketResolved,
211}
212
213impl PolymarketOrderStatus {
214    pub(crate) fn parse_wire(value: &str) -> Option<(Self, Option<&str>)> {
215        // Match the longest known variant first so `CANCELED_MARKET_RESOLVED`
216        // is not truncated to `CANCELED` when a reason suffix is present.
217        const VARIANTS: &[(&str, PolymarketOrderStatus)] = &[
218            (
219                "CANCELED_MARKET_RESOLVED",
220                PolymarketOrderStatus::CanceledMarketResolved,
221            ),
222            ("INVALID", PolymarketOrderStatus::Invalid),
223            ("LIVE", PolymarketOrderStatus::Live),
224            ("DELAYED", PolymarketOrderStatus::Delayed),
225            ("MATCHED", PolymarketOrderStatus::Matched),
226            ("UNMATCHED", PolymarketOrderStatus::Unmatched),
227            ("CANCELED", PolymarketOrderStatus::Canceled),
228        ];
229
230        let value = value.strip_prefix("ORDER_STATUS_").unwrap_or(value);
231
232        if let Ok(status) = <Self as std::str::FromStr>::from_str(value) {
233            return Some((status, None));
234        }
235
236        VARIANTS.iter().find_map(|(prefix, status)| {
237            value
238                .strip_prefix(prefix)
239                .and_then(|suffix| suffix.strip_prefix('_'))
240                .map(|reason| (*status, Some(reason)))
241        })
242    }
243}
244
245impl<'de> Deserialize<'de> for PolymarketOrderStatus {
246    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
247    where
248        D: serde::Deserializer<'de>,
249    {
250        let s = String::deserialize(deserializer)?;
251
252        Self::parse_wire(&s)
253            .map(|(status, _)| status)
254            .ok_or_else(|| serde::de::Error::custom(format!("Unknown PolymarketOrderStatus: {s}")))
255    }
256}
257
258/// Trade settlement status on the Polymarket exchange.
259#[derive(
260    Clone, Copy, Debug, PartialEq, Eq, Hash, StrumDisplay, EnumString, Serialize, Deserialize,
261)]
262#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
263#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
264pub enum PolymarketTradeStatus {
265    /// Sent to the executor service for on-chain submission.
266    #[serde(alias = "TRADE_STATUS_MATCHED")]
267    Matched,
268    /// Matched before the on-chain transaction was broadcast.
269    #[serde(alias = "TRADE_STATUS_MATCHED_NOT_BROADCASTED")]
270    MatchedNotBroadcasted,
271    /// Mined on-chain, no finality threshold yet.
272    #[serde(alias = "TRADE_STATUS_MINED")]
273    Mined,
274    /// Strong probabilistic finality achieved.
275    #[serde(alias = "TRADE_STATUS_CONFIRMED")]
276    Confirmed,
277    /// Transaction failed, being retried by the operator.
278    #[serde(alias = "TRADE_STATUS_RETRYING")]
279    Retrying,
280    /// Permanently failed, no more retries.
281    #[serde(alias = "TRADE_STATUS_FAILED")]
282    Failed,
283}
284
285impl PolymarketTradeStatus {
286    /// Returns `true` if this status represents a finalized trade.
287    #[must_use]
288    pub const fn is_finalized(&self) -> bool {
289        matches!(self, Self::Confirmed)
290    }
291
292    /// Returns `true` while settlement can still succeed or fail.
293    #[must_use]
294    pub const fn is_pending_settlement(&self) -> bool {
295        matches!(
296            self,
297            Self::Matched | Self::MatchedNotBroadcasted | Self::Mined | Self::Retrying
298        )
299    }
300}
301
302impl From<PolymarketOrderSide> for OrderSide {
303    fn from(value: PolymarketOrderSide) -> Self {
304        match value {
305            PolymarketOrderSide::Buy => Self::Buy,
306            PolymarketOrderSide::Sell => Self::Sell,
307        }
308    }
309}
310
311impl From<OrderSide> for PolymarketOrderSide {
312    fn from(value: OrderSide) -> Self {
313        match value {
314            OrderSide::Buy => Self::Buy,
315            OrderSide::Sell => Self::Sell,
316        }
317    }
318}
319
320impl From<PolymarketOrderSide> for AggressorSide {
321    fn from(value: PolymarketOrderSide) -> Self {
322        match value {
323            PolymarketOrderSide::Buy => Self::Buy,
324            PolymarketOrderSide::Sell => Self::Sell,
325        }
326    }
327}
328
329impl From<PolymarketOrderType> for TimeInForce {
330    fn from(value: PolymarketOrderType) -> Self {
331        match value {
332            PolymarketOrderType::GTC => Self::Gtc,
333            PolymarketOrderType::GTD => Self::Gtd,
334            PolymarketOrderType::FOK => Self::Fok,
335            // Fill-And-Kill is equivalent to Immediate-Or-Cancel
336            PolymarketOrderType::FAK => Self::Ioc,
337        }
338    }
339}
340
341impl TryFrom<TimeInForce> for PolymarketOrderType {
342    type Error = anyhow::Error;
343
344    fn try_from(value: TimeInForce) -> anyhow::Result<Self> {
345        match value {
346            TimeInForce::Gtc => Ok(Self::GTC),
347            TimeInForce::Gtd => Ok(Self::GTD),
348            TimeInForce::Fok => Ok(Self::FOK),
349            TimeInForce::Ioc => Ok(Self::FAK),
350            _ => anyhow::bail!("Unsupported `TimeInForce` for Polymarket: {value:?}"),
351        }
352    }
353}
354
355impl PolymarketOrderType {
356    pub(crate) fn from_market_time_in_force(value: TimeInForce) -> anyhow::Result<Self> {
357        match value {
358            TimeInForce::Fok => Ok(Self::FOK),
359            TimeInForce::Ioc => Ok(Self::FAK),
360            _ => anyhow::bail!("Unsupported `TimeInForce` for Polymarket market order: {value:?}"),
361        }
362    }
363}
364
365impl From<PolymarketOrderStatus> for OrderStatus {
366    fn from(value: PolymarketOrderStatus) -> Self {
367        match value {
368            PolymarketOrderStatus::Invalid => Self::Rejected,
369            PolymarketOrderStatus::Live => Self::Accepted,
370            PolymarketOrderStatus::Delayed => Self::Accepted,
371            PolymarketOrderStatus::Matched => Self::Filled,
372            // Placement failure (never became live), treat as rejected
373            PolymarketOrderStatus::Unmatched => Self::Rejected,
374            PolymarketOrderStatus::Canceled => Self::Canceled,
375            // Market resolved = order expired due to market settlement
376            PolymarketOrderStatus::CanceledMarketResolved => Self::Expired,
377        }
378    }
379}
380
381#[cfg(test)]
382mod tests {
383    use rstest::rstest;
384
385    use super::*;
386
387    #[rstest]
388    fn test_signature_type_serializes_as_u8() {
389        assert_eq!(
390            serde_json::to_string(&PolymarketSignatureType::Eoa).unwrap(),
391            "0"
392        );
393        assert_eq!(
394            serde_json::to_string(&PolymarketSignatureType::PolyProxy).unwrap(),
395            "1"
396        );
397        assert_eq!(
398            serde_json::to_string(&PolymarketSignatureType::PolyGnosisSafe).unwrap(),
399            "2"
400        );
401        assert_eq!(
402            serde_json::to_string(&PolymarketSignatureType::Poly1271).unwrap(),
403            "3"
404        );
405    }
406
407    #[rstest]
408    fn test_signature_type_deserializes_from_u8() {
409        assert_eq!(
410            serde_json::from_str::<PolymarketSignatureType>("0").unwrap(),
411            PolymarketSignatureType::Eoa
412        );
413        assert_eq!(
414            serde_json::from_str::<PolymarketSignatureType>("1").unwrap(),
415            PolymarketSignatureType::PolyProxy
416        );
417        assert_eq!(
418            serde_json::from_str::<PolymarketSignatureType>("2").unwrap(),
419            PolymarketSignatureType::PolyGnosisSafe
420        );
421        assert_eq!(
422            serde_json::from_str::<PolymarketSignatureType>("3").unwrap(),
423            PolymarketSignatureType::Poly1271
424        );
425    }
426
427    #[rstest]
428    fn test_order_side_serde_screaming_snake() {
429        assert_eq!(
430            serde_json::to_string(&PolymarketOrderSide::Buy).unwrap(),
431            "\"BUY\""
432        );
433        assert_eq!(
434            serde_json::from_str::<PolymarketOrderSide>("\"SELL\"").unwrap(),
435            PolymarketOrderSide::Sell
436        );
437    }
438
439    #[rstest]
440    fn test_event_type_serde_screaming_snake() {
441        assert_eq!(
442            serde_json::to_string(&PolymarketEventType::Placement).unwrap(),
443            "\"PLACEMENT\""
444        );
445        assert_eq!(
446            serde_json::from_str::<PolymarketEventType>("\"TRADE\"").unwrap(),
447            PolymarketEventType::Trade
448        );
449    }
450
451    #[rstest]
452    fn test_order_status_serde_screaming_snake() {
453        assert_eq!(
454            serde_json::to_string(&PolymarketOrderStatus::Live).unwrap(),
455            "\"LIVE\""
456        );
457        assert_eq!(
458            serde_json::from_str::<PolymarketOrderStatus>("\"CANCELED_MARKET_RESOLVED\"").unwrap(),
459            PolymarketOrderStatus::CanceledMarketResolved
460        );
461    }
462
463    #[rstest]
464    fn test_order_status_deserializes_openapi_prefix() {
465        assert_eq!(
466            serde_json::from_str::<PolymarketOrderStatus>("\"ORDER_STATUS_LIVE\"").unwrap(),
467            PolymarketOrderStatus::Live
468        );
469        assert_eq!(
470            serde_json::from_str::<PolymarketOrderStatus>("\"ORDER_STATUS_CANCELED_reason\"")
471                .unwrap(),
472            PolymarketOrderStatus::Canceled
473        );
474    }
475
476    #[rstest]
477    #[case(
478        "\"CANCELED_order couldn't be fully filled. FOK orders are fully filled or killed.\"",
479        PolymarketOrderStatus::Canceled
480    )]
481    #[case("\"CANCELED_some other reason\"", PolymarketOrderStatus::Canceled)]
482    #[case(
483        "\"CANCELED_MARKET_RESOLVED_resolved at block 12345\"",
484        PolymarketOrderStatus::CanceledMarketResolved
485    )]
486    #[case(
487        "\"UNMATCHED_insufficient liquidity\"",
488        PolymarketOrderStatus::Unmatched
489    )]
490    fn test_order_status_strips_reason_suffix(
491        #[case] raw: &str,
492        #[case] expected: PolymarketOrderStatus,
493    ) {
494        assert_eq!(
495            serde_json::from_str::<PolymarketOrderStatus>(raw).unwrap(),
496            expected,
497        );
498    }
499
500    #[rstest]
501    fn test_order_status_rejects_unknown() {
502        assert!(serde_json::from_str::<PolymarketOrderStatus>("\"UNKNOWN_STATUS\"").is_err());
503        assert!(serde_json::from_str::<PolymarketOrderStatus>("\"\"").is_err());
504    }
505
506    #[rstest]
507    fn test_trade_status_serde_screaming_snake() {
508        assert_eq!(
509            serde_json::to_string(&PolymarketTradeStatus::Confirmed).unwrap(),
510            "\"CONFIRMED\""
511        );
512        assert_eq!(
513            serde_json::from_str::<PolymarketTradeStatus>("\"RETRYING\"").unwrap(),
514            PolymarketTradeStatus::Retrying
515        );
516    }
517
518    #[rstest]
519    fn test_trade_status_deserializes_openapi_prefix() {
520        assert_eq!(
521            serde_json::from_str::<PolymarketTradeStatus>("\"TRADE_STATUS_CONFIRMED\"").unwrap(),
522            PolymarketTradeStatus::Confirmed
523        );
524    }
525
526    #[rstest]
527    #[case("\"MATCHED_NOT_BROADCASTED\"")]
528    #[case("\"TRADE_STATUS_MATCHED_NOT_BROADCASTED\"")]
529    fn test_trade_status_deserializes_matched_not_broadcasted(#[case] wire: &str) {
530        assert_eq!(
531            serde_json::from_str::<PolymarketTradeStatus>(wire).unwrap(),
532            PolymarketTradeStatus::MatchedNotBroadcasted
533        );
534    }
535
536    #[rstest]
537    #[case(PolymarketOrderSide::Buy, OrderSide::Buy)]
538    #[case(PolymarketOrderSide::Sell, OrderSide::Sell)]
539    fn test_order_side_to_nautilus(#[case] poly: PolymarketOrderSide, #[case] expected: OrderSide) {
540        assert_eq!(OrderSide::from(poly), expected);
541    }
542
543    #[rstest]
544    #[case(OrderSide::Buy, PolymarketOrderSide::Buy)]
545    #[case(OrderSide::Sell, PolymarketOrderSide::Sell)]
546    fn test_nautilus_order_side_to_poly(
547        #[case] nautilus: OrderSide,
548        #[case] expected: PolymarketOrderSide,
549    ) {
550        assert_eq!(PolymarketOrderSide::from(nautilus), expected);
551    }
552
553    #[rstest]
554    #[case(PolymarketOrderSide::Buy, AggressorSide::Buy)]
555    #[case(PolymarketOrderSide::Sell, AggressorSide::Sell)]
556    fn test_order_side_to_aggressor(
557        #[case] poly: PolymarketOrderSide,
558        #[case] expected: AggressorSide,
559    ) {
560        assert_eq!(AggressorSide::from(poly), expected);
561    }
562
563    #[rstest]
564    #[case(PolymarketOrderType::GTC, TimeInForce::Gtc)]
565    #[case(PolymarketOrderType::GTD, TimeInForce::Gtd)]
566    #[case(PolymarketOrderType::FOK, TimeInForce::Fok)]
567    #[case(PolymarketOrderType::FAK, TimeInForce::Ioc)]
568    fn test_order_type_to_time_in_force(
569        #[case] poly: PolymarketOrderType,
570        #[case] expected: TimeInForce,
571    ) {
572        assert_eq!(TimeInForce::from(poly), expected);
573    }
574
575    #[rstest]
576    #[case(TimeInForce::Gtc, PolymarketOrderType::GTC)]
577    #[case(TimeInForce::Gtd, PolymarketOrderType::GTD)]
578    #[case(TimeInForce::Fok, PolymarketOrderType::FOK)]
579    #[case(TimeInForce::Ioc, PolymarketOrderType::FAK)]
580    fn test_time_in_force_to_order_type(
581        #[case] tif: TimeInForce,
582        #[case] expected: PolymarketOrderType,
583    ) {
584        assert_eq!(PolymarketOrderType::try_from(tif).unwrap(), expected);
585    }
586
587    #[rstest]
588    #[case(TimeInForce::Ioc, PolymarketOrderType::FAK)]
589    #[case(TimeInForce::Fok, PolymarketOrderType::FOK)]
590    fn test_market_time_in_force_to_order_type(
591        #[case] tif: TimeInForce,
592        #[case] expected: PolymarketOrderType,
593    ) {
594        assert_eq!(
595            PolymarketOrderType::from_market_time_in_force(tif).unwrap(),
596            expected,
597        );
598    }
599
600    #[rstest]
601    #[case(TimeInForce::Gtc)]
602    #[case(TimeInForce::Gtd)]
603    fn test_market_time_in_force_to_order_type_rejects_non_market_tif(#[case] tif: TimeInForce) {
604        assert!(PolymarketOrderType::from_market_time_in_force(tif).is_err());
605    }
606
607    #[rstest]
608    #[case(PolymarketOrderStatus::Invalid, OrderStatus::Rejected)]
609    #[case(PolymarketOrderStatus::Live, OrderStatus::Accepted)]
610    #[case(PolymarketOrderStatus::Delayed, OrderStatus::Accepted)]
611    #[case(PolymarketOrderStatus::Matched, OrderStatus::Filled)]
612    #[case(PolymarketOrderStatus::Unmatched, OrderStatus::Rejected)]
613    #[case(PolymarketOrderStatus::Canceled, OrderStatus::Canceled)]
614    #[case(PolymarketOrderStatus::CanceledMarketResolved, OrderStatus::Expired)]
615    fn test_order_status_to_nautilus(
616        #[case] poly: PolymarketOrderStatus,
617        #[case] expected: OrderStatus,
618    ) {
619        assert_eq!(OrderStatus::from(poly), expected);
620    }
621
622    #[rstest]
623    fn test_trade_status_is_finalized() {
624        assert!(!PolymarketTradeStatus::Mined.is_finalized());
625        assert!(PolymarketTradeStatus::Confirmed.is_finalized());
626        assert!(!PolymarketTradeStatus::Matched.is_finalized());
627        assert!(!PolymarketTradeStatus::Retrying.is_finalized());
628        assert!(!PolymarketTradeStatus::Failed.is_finalized());
629    }
630
631    #[rstest]
632    fn test_trade_status_is_pending_settlement() {
633        assert!(PolymarketTradeStatus::Matched.is_pending_settlement());
634        assert!(PolymarketTradeStatus::MatchedNotBroadcasted.is_pending_settlement());
635        assert!(PolymarketTradeStatus::Mined.is_pending_settlement());
636        assert!(PolymarketTradeStatus::Retrying.is_pending_settlement());
637        assert!(!PolymarketTradeStatus::Confirmed.is_pending_settlement());
638        assert!(!PolymarketTradeStatus::Failed.is_pending_settlement());
639    }
640}