prediction-market-agent-tooling 0.49.0__py3-none-any.whl → 0.49.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. prediction_market_agent_tooling/abis/debuggingcontract.abi.json +29 -0
  2. prediction_market_agent_tooling/abis/omen_agentresultmapping.abi.json +171 -0
  3. prediction_market_agent_tooling/benchmark/benchmark.py +0 -93
  4. prediction_market_agent_tooling/config.py +16 -0
  5. prediction_market_agent_tooling/deploy/agent.py +61 -6
  6. prediction_market_agent_tooling/markets/agent_market.py +3 -3
  7. prediction_market_agent_tooling/markets/data_models.py +1 -1
  8. prediction_market_agent_tooling/markets/metaculus/metaculus.py +1 -1
  9. prediction_market_agent_tooling/markets/omen/data_models.py +240 -5
  10. prediction_market_agent_tooling/markets/omen/omen.py +43 -25
  11. prediction_market_agent_tooling/markets/omen/omen_contracts.py +179 -33
  12. prediction_market_agent_tooling/markets/omen/omen_subgraph_handler.py +35 -0
  13. prediction_market_agent_tooling/monitor/monitor.py +3 -3
  14. prediction_market_agent_tooling/monitor/monitor_app.py +2 -2
  15. prediction_market_agent_tooling/tools/contract.py +50 -1
  16. prediction_market_agent_tooling/tools/ipfs/ipfs_handler.py +33 -0
  17. prediction_market_agent_tooling/tools/langfuse_client_utils.py +23 -8
  18. prediction_market_agent_tooling/tools/utils.py +28 -4
  19. prediction_market_agent_tooling/tools/web3_utils.py +7 -0
  20. {prediction_market_agent_tooling-0.49.0.dist-info → prediction_market_agent_tooling-0.49.1.dist-info}/METADATA +2 -1
  21. {prediction_market_agent_tooling-0.49.0.dist-info → prediction_market_agent_tooling-0.49.1.dist-info}/RECORD +24 -21
  22. {prediction_market_agent_tooling-0.49.0.dist-info → prediction_market_agent_tooling-0.49.1.dist-info}/LICENSE +0 -0
  23. {prediction_market_agent_tooling-0.49.0.dist-info → prediction_market_agent_tooling-0.49.1.dist-info}/WHEEL +0 -0
  24. {prediction_market_agent_tooling-0.49.0.dist-info → prediction_market_agent_tooling-0.49.1.dist-info}/entry_points.txt +0 -0
@@ -1,7 +1,8 @@
1
1
  import typing as t
2
2
  from datetime import datetime
3
3
 
4
- from pydantic import BaseModel
4
+ import pytz
5
+ from pydantic import BaseModel, ConfigDict, Field, computed_field
5
6
  from web3 import Web3
6
7
 
7
8
  from prediction_market_agent_tooling.gtypes import (
@@ -13,6 +14,7 @@ from prediction_market_agent_tooling.gtypes import (
13
14
  OmenOutcomeToken,
14
15
  Probability,
15
16
  Wei,
17
+ wei_type,
16
18
  xDai,
17
19
  )
18
20
  from prediction_market_agent_tooling.markets.data_models import (
@@ -37,6 +39,7 @@ INVALID_ANSWER_HEX_BYTES = HexBytes(INVALID_ANSWER)
37
39
  INVALID_ANSWER_STR = HexStr(INVALID_ANSWER_HEX_BYTES.hex())
38
40
  OMEN_BASE_URL = "https://aiomen.eth.limo"
39
41
  PRESAGIO_BASE_URL = "https://presagio.pages.dev"
42
+ TEST_CATEGORY = "test" # This category is hidden on Presagio for testing purposes.
40
43
 
41
44
 
42
45
  def get_boolean_outcome(outcome_str: str) -> bool:
@@ -207,8 +210,6 @@ class OmenMarket(BaseModel):
207
210
  creationTimestamp: int
208
211
  condition: Condition
209
212
  question: Question
210
- lastActiveDay: int
211
- lastActiveHour: int
212
213
 
213
214
  @property
214
215
  def openingTimestamp(self) -> int:
@@ -218,7 +219,7 @@ class OmenMarket(BaseModel):
218
219
 
219
220
  @property
220
221
  def opening_datetime(self) -> datetime:
221
- return datetime.fromtimestamp(self.openingTimestamp)
222
+ return datetime.fromtimestamp(self.openingTimestamp, tz=pytz.UTC)
222
223
 
223
224
  @property
224
225
  def close_time(self) -> datetime:
@@ -376,6 +377,96 @@ class OmenMarket(BaseModel):
376
377
  def url(self) -> str:
377
378
  return f"{PRESAGIO_BASE_URL}/markets?id={self.id}"
378
379
 
380
+ @staticmethod
381
+ def from_created_market(model: "CreatedMarket") -> "OmenMarket":
382
+ """
383
+ OmenMarket is meant to be retrieved from subgraph, however in tests against local chain it's very handy to create it out of `CreatedMarket`,
384
+ which is collection of events that are emitted during the market creation in omen_create_market_tx function.
385
+ """
386
+ if len(model.market_event.conditionIds) != 1:
387
+ raise ValueError(
388
+ f"Unexpected number of conditions: {len(model.market_event.conditionIds)}"
389
+ )
390
+ outcome_token_amounts = model.funding_event.outcome_token_amounts
391
+ return OmenMarket(
392
+ id=HexAddress(
393
+ HexStr(model.market_event.fixedProductMarketMaker.lower())
394
+ ), # Lowering to be identical with subgraph's output.
395
+ title=model.question_event.parsed_question.question,
396
+ creator=HexAddress(
397
+ HexStr(model.market_event.creator.lower())
398
+ ), # Lowering to be identical with subgraph's output.
399
+ category=model.question_event.parsed_question.category,
400
+ collateralVolume=Wei(0), # No volume possible yet.
401
+ liquidityParameter=calculate_liquidity_parameter(outcome_token_amounts),
402
+ usdVolume=USD(0), # No volume possible yet.
403
+ fee=model.fee,
404
+ collateralToken=HexAddress(
405
+ HexStr(model.market_event.collateralToken.lower())
406
+ ), # Lowering to be identical with subgraph's output.
407
+ outcomes=model.question_event.parsed_question.outcomes,
408
+ outcomeTokenAmounts=outcome_token_amounts,
409
+ outcomeTokenMarginalPrices=calculate_marginal_prices(outcome_token_amounts),
410
+ answerFinalizedTimestamp=None, # It's a fresh market.
411
+ currentAnswer=None, # It's a fresh market.
412
+ creationTimestamp=model.market_creation_timestamp,
413
+ condition=Condition(
414
+ id=model.market_event.conditionIds[0],
415
+ outcomeSlotCount=len(model.question_event.parsed_question.outcomes),
416
+ ),
417
+ question=Question(
418
+ id=model.question_event.question_id,
419
+ title=model.question_event.parsed_question.question,
420
+ data=model.question_event.question, # Question in the event holds the "raw" data.
421
+ templateId=model.question_event.template_id,
422
+ outcomes=model.question_event.parsed_question.outcomes,
423
+ isPendingArbitration=False, # Can not be, it's a fresh market.
424
+ openingTimestamp=model.question_event.opening_ts,
425
+ answerFinalizedTimestamp=None, # It's a new one, can not be.
426
+ currentAnswer=None, # It's a new one, no answer yet.
427
+ ),
428
+ )
429
+
430
+
431
+ def calculate_liquidity_parameter(
432
+ outcome_token_amounts: list[OmenOutcomeToken],
433
+ ) -> Wei:
434
+ """
435
+ Converted to Python from https://github.com/protofire/omen-subgraph/blob/f92bbfb6fa31ed9cd5985c416a26a2f640837d8b/src/utils/fpmm.ts#L171.
436
+ """
437
+ amounts_product = 1.0
438
+ for amount in outcome_token_amounts:
439
+ amounts_product *= amount
440
+ n = len(outcome_token_amounts)
441
+ liquidity_parameter = amounts_product ** (1.0 / n)
442
+ return wei_type(liquidity_parameter)
443
+
444
+
445
+ def calculate_marginal_prices(
446
+ outcome_token_amounts: list[OmenOutcomeToken],
447
+ ) -> list[xDai] | None:
448
+ """
449
+ Converted to Python from https://github.com/protofire/omen-subgraph/blob/f92bbfb6fa31ed9cd5985c416a26a2f640837d8b/src/utils/fpmm.ts#L197.
450
+ """
451
+ all_non_zero = all(x != 0 for x in outcome_token_amounts)
452
+ if not all_non_zero:
453
+ return None
454
+
455
+ n_outcomes = len(outcome_token_amounts)
456
+ weights = []
457
+
458
+ for i in range(n_outcomes):
459
+ weight = 1.0
460
+ for j in range(n_outcomes):
461
+ if i != j:
462
+ weight *= outcome_token_amounts[j]
463
+ weights.append(weight)
464
+
465
+ sum_weights = sum(weights)
466
+
467
+ marginal_prices = [weights[i] / sum_weights for i in range(n_outcomes)]
468
+ return [xDai(mp) for mp in marginal_prices]
469
+
379
470
 
380
471
  class OmenBetCreator(BaseModel):
381
472
  id: HexAddress
@@ -400,7 +491,7 @@ class OmenBet(BaseModel):
400
491
 
401
492
  @property
402
493
  def creation_datetime(self) -> datetime:
403
- return datetime.fromtimestamp(self.creationTimestamp)
494
+ return datetime.fromtimestamp(self.creationTimestamp, tz=pytz.UTC)
404
495
 
405
496
  @property
406
497
  def boolean_outcome(self) -> bool:
@@ -533,3 +624,147 @@ class RealityAnswers(BaseModel):
533
624
 
534
625
  class RealityAnswersResponse(BaseModel):
535
626
  data: RealityAnswers
627
+
628
+
629
+ def format_realitio_question(
630
+ question: str,
631
+ outcomes: list[str],
632
+ category: str,
633
+ language: str,
634
+ template_id: int,
635
+ ) -> str:
636
+ """If you add a new template id here, also add to the parsing function below."""
637
+ if template_id == 2:
638
+ return "␟".join(
639
+ [
640
+ question,
641
+ ",".join(f'"{o}"' for o in outcomes),
642
+ category,
643
+ language,
644
+ ]
645
+ )
646
+
647
+ raise ValueError(f"Unsupported template id {template_id}.")
648
+
649
+
650
+ def parse_realitio_question(question_raw: str, template_id: int) -> "ParsedQuestion":
651
+ """If you add a new template id here, also add to the encoding function above."""
652
+ if template_id == 2:
653
+ question, outcomes_raw, category, language = question_raw.split("␟")
654
+ outcomes = [o.strip('"') for o in outcomes_raw.split(",")]
655
+ return ParsedQuestion(
656
+ question=question, outcomes=outcomes, category=category, language=language
657
+ )
658
+
659
+ raise ValueError(f"Unsupported template id {template_id}.")
660
+
661
+
662
+ class ParsedQuestion(BaseModel):
663
+ question: str
664
+ outcomes: list[str]
665
+ language: str
666
+ category: str
667
+
668
+
669
+ class RealitioLogNewQuestionEvent(BaseModel):
670
+ question_id: HexBytes
671
+ user: HexAddress
672
+ template_id: int
673
+ question: str # Be aware, this is question in format of format_realitio_question function, it's raw data.
674
+ content_hash: HexBytes
675
+ arbitrator: HexAddress
676
+ timeout: int
677
+ opening_ts: int
678
+ nonce: int
679
+ created: int
680
+
681
+ @property
682
+ def user_checksummed(self) -> ChecksumAddress:
683
+ return Web3.to_checksum_address(self.user)
684
+
685
+ @property
686
+ def parsed_question(self) -> ParsedQuestion:
687
+ return parse_realitio_question(
688
+ question_raw=self.question, template_id=self.template_id
689
+ )
690
+
691
+
692
+ class OmenFixedProductMarketMakerCreationEvent(BaseModel):
693
+ creator: HexAddress
694
+ fixedProductMarketMaker: HexAddress
695
+ conditionalTokens: HexAddress
696
+ collateralToken: HexAddress
697
+ conditionIds: list[HexBytes]
698
+ fee: int
699
+
700
+ @property
701
+ def creator_checksummed(self) -> ChecksumAddress:
702
+ return Web3.to_checksum_address(self.creator)
703
+
704
+ @property
705
+ def fixed_product_market_maker_checksummed(self) -> ChecksumAddress:
706
+ return Web3.to_checksum_address(self.fixedProductMarketMaker)
707
+
708
+ @property
709
+ def conditional_tokens_checksummed(self) -> ChecksumAddress:
710
+ return Web3.to_checksum_address(self.conditionalTokens)
711
+
712
+ @property
713
+ def collateral_token_checksummed(self) -> ChecksumAddress:
714
+ return Web3.to_checksum_address(self.collateralToken)
715
+
716
+
717
+ class ConditionPreparationEvent(BaseModel):
718
+ conditionId: HexBytes
719
+ oracle: HexAddress
720
+ questionId: HexBytes
721
+ outcomeSlotCount: int
722
+
723
+
724
+ class FPMMFundingAddedEvent(BaseModel):
725
+ funder: HexAddress
726
+ amountsAdded: list[OmenOutcomeToken]
727
+ sharesMinted: Wei
728
+
729
+ @property
730
+ def outcome_token_amounts(self) -> list[OmenOutcomeToken]:
731
+ # Just renaming so we remember what it is.
732
+ return self.amountsAdded
733
+
734
+
735
+ class CreatedMarket(BaseModel):
736
+ market_creation_timestamp: int
737
+ market_event: OmenFixedProductMarketMakerCreationEvent
738
+ funding_event: FPMMFundingAddedEvent
739
+ condition_id: HexBytes
740
+ question_event: RealitioLogNewQuestionEvent
741
+ condition_event: ConditionPreparationEvent | None
742
+ initial_funds: Wei
743
+ fee: Wei
744
+ distribution_hint: list[OmenOutcomeToken] | None
745
+
746
+
747
+ class ContractPrediction(BaseModel):
748
+ model_config = ConfigDict(populate_by_name=True)
749
+ publisher: str = Field(..., alias="publisherAddress")
750
+ ipfs_hash: HexBytes = Field(..., alias="ipfsHash")
751
+ tx_hashes: list[HexBytes] = Field(..., alias="txHashes")
752
+ estimated_probability_bps: int = Field(..., alias="estimatedProbabilityBps")
753
+
754
+ @computed_field # type: ignore[prop-decorator] # Mypy issue: https://github.com/python/mypy/issues/14461
755
+ @property
756
+ def publisher_checksummed(self) -> ChecksumAddress:
757
+ return Web3.to_checksum_address(self.publisher)
758
+
759
+ @staticmethod
760
+ def from_tuple(values: tuple[t.Any]) -> "ContractPrediction":
761
+ data = {k: v for k, v in zip(ContractPrediction.model_fields.keys(), values)}
762
+ return ContractPrediction.model_validate(data)
763
+
764
+
765
+ class IPFSAgentResult(BaseModel):
766
+ reasoning: str
767
+
768
+ model_config = ConfigDict(
769
+ extra="forbid",
770
+ )
@@ -1,16 +1,16 @@
1
1
  import sys
2
2
  import typing as t
3
- from datetime import datetime
3
+ from datetime import datetime, timedelta
4
4
 
5
5
  import tenacity
6
6
  from web3 import Web3
7
- from web3.constants import HASH_ZERO
8
7
 
9
8
  from prediction_market_agent_tooling.config import APIKeys
10
9
  from prediction_market_agent_tooling.gtypes import (
11
10
  ChecksumAddress,
12
11
  HexAddress,
13
12
  HexStr,
13
+ OmenOutcomeToken,
14
14
  OutcomeStr,
15
15
  Probability,
16
16
  Wei,
@@ -37,6 +37,8 @@ from prediction_market_agent_tooling.markets.omen.data_models import (
37
37
  OMEN_TRUE_OUTCOME,
38
38
  PRESAGIO_BASE_URL,
39
39
  Condition,
40
+ ConditionPreparationEvent,
41
+ CreatedMarket,
40
42
  OmenBet,
41
43
  OmenMarket,
42
44
  OmenUserPosition,
@@ -44,7 +46,7 @@ from prediction_market_agent_tooling.markets.omen.data_models import (
44
46
  get_boolean_outcome,
45
47
  )
46
48
  from prediction_market_agent_tooling.markets.omen.omen_contracts import (
47
- OMEN_DEFAULT_MARKET_FEE,
49
+ OMEN_DEFAULT_MARKET_FEE_PERC,
48
50
  Arbitrator,
49
51
  OmenConditionalTokenContract,
50
52
  OmenFixedProductMarketMakerContract,
@@ -52,6 +54,7 @@ from prediction_market_agent_tooling.markets.omen.omen_contracts import (
52
54
  OmenOracleContract,
53
55
  OmenRealitioContract,
54
56
  WrappedxDaiContract,
57
+ build_parent_collection_id,
55
58
  )
56
59
  from prediction_market_agent_tooling.markets.omen.omen_subgraph_handler import (
57
60
  OmenSubgraphHandler,
@@ -71,6 +74,7 @@ from prediction_market_agent_tooling.tools.utils import (
71
74
  )
72
75
  from prediction_market_agent_tooling.tools.web3_utils import (
73
76
  add_fraction,
77
+ get_receipt_block_timestamp,
74
78
  remove_fraction,
75
79
  wei_to_xdai,
76
80
  xdai_to_wei,
@@ -325,6 +329,10 @@ class OmenAgentMarket(AgentMarket):
325
329
 
326
330
  omen_redeem_full_position_tx(api_keys=api_keys, market=self)
327
331
 
332
+ @staticmethod
333
+ def from_created_market(model: "CreatedMarket") -> "OmenAgentMarket":
334
+ return OmenAgentMarket.from_data_model(OmenMarket.from_created_market(model))
335
+
328
336
  @staticmethod
329
337
  def from_data_model(model: OmenMarket) -> "OmenAgentMarket":
330
338
  return OmenAgentMarket(
@@ -674,7 +682,7 @@ def omen_buy_outcome_tx(
674
682
  amount_wei = xdai_to_wei(amount)
675
683
 
676
684
  market_contract: OmenFixedProductMarketMakerContract = market.get_contract()
677
- collateral_token_contract = market_contract.get_collateral_token_contract()
685
+ collateral_token_contract = market_contract.get_collateral_token_contract(web3)
678
686
 
679
687
  # In case of ERC4626, obtained (for example) sDai out of xDai could be lower than the `amount_wei`, so we need to handle it.
680
688
  amount_wei_to_buy = collateral_token_contract.get_in_shares(amount_wei, web3)
@@ -751,7 +759,7 @@ def omen_sell_outcome_tx(
751
759
 
752
760
  market_contract: OmenFixedProductMarketMakerContract = market.get_contract()
753
761
  conditional_token_contract = OmenConditionalTokenContract()
754
- collateral_token_contract = market_contract.get_collateral_token_contract()
762
+ collateral_token_contract = market_contract.get_collateral_token_contract(web3)
755
763
 
756
764
  # Verify, that markets uses conditional tokens that we expect.
757
765
  if (
@@ -832,10 +840,13 @@ def omen_create_market_tx(
832
840
  language: str,
833
841
  outcomes: list[str],
834
842
  auto_deposit: bool,
835
- fee: float = OMEN_DEFAULT_MARKET_FEE,
843
+ finalization_timeout: timedelta = timedelta(days=1),
844
+ fee_perc: float = OMEN_DEFAULT_MARKET_FEE_PERC,
845
+ distribution_hint: list[OmenOutcomeToken] | None = None,
836
846
  collateral_token_address: ChecksumAddress = WrappedxDaiContract().address,
847
+ arbitrator: Arbitrator = Arbitrator.KLEROS_31_JURORS_WITH_APPEAL,
837
848
  web3: Web3 | None = None,
838
- ) -> ChecksumAddress:
849
+ ) -> CreatedMarket:
839
850
  """
840
851
  Based on omen-exchange TypeScript code: https://github.com/protofire/omen-exchange/blob/b0b9a3e71b415d6becf21fe428e1c4fc0dad2e80/app/src/services/cpk/cpk.ts#L308
841
852
  """
@@ -873,28 +884,30 @@ def omen_create_market_tx(
873
884
  )
874
885
 
875
886
  # Create the question on Realitio.
876
- question_id = realitio_contract.askQuestion(
887
+ question_event = realitio_contract.askQuestion(
877
888
  api_keys=api_keys,
878
889
  question=question,
879
890
  category=category,
880
891
  outcomes=outcomes,
881
892
  language=language,
882
- arbitrator=Arbitrator.KLEROS,
893
+ arbitrator=arbitrator,
883
894
  opening=closing_time, # The question is opened at the closing time of the market.
895
+ timeout=finalization_timeout,
884
896
  web3=web3,
885
897
  )
886
898
 
887
899
  # Construct the condition id.
900
+ cond_event: ConditionPreparationEvent | None = None
888
901
  condition_id = conditional_token_contract.getConditionId(
889
- question_id=question_id,
902
+ question_id=question_event.question_id,
890
903
  oracle_address=oracle_contract.address,
891
904
  outcomes_slot_count=len(outcomes),
892
905
  web3=web3,
893
906
  )
894
907
  if not conditional_token_contract.does_condition_exists(condition_id, web3=web3):
895
- conditional_token_contract.prepareCondition(
908
+ cond_event = conditional_token_contract.prepareCondition(
896
909
  api_keys=api_keys,
897
- question_id=question_id,
910
+ question_id=question_event.question_id,
898
911
  oracle_address=oracle_contract.address,
899
912
  outcomes_slot_count=len(outcomes),
900
913
  web3=web3,
@@ -914,10 +927,16 @@ def omen_create_market_tx(
914
927
  )
915
928
 
916
929
  # Create the market.
917
- create_market_receipt_tx = factory_contract.create2FixedProductMarketMaker(
930
+ fee = xdai_to_wei(xdai_type(fee_perc))
931
+ (
932
+ market_event,
933
+ funding_event,
934
+ receipt_tx,
935
+ ) = factory_contract.create2FixedProductMarketMaker(
918
936
  api_keys=api_keys,
919
937
  condition_id=condition_id,
920
938
  fee=fee,
939
+ distribution_hint=distribution_hint,
921
940
  initial_funds_wei=initial_funds_in_shares,
922
941
  collateral_token_address=collateral_token_contract.address,
923
942
  web3=web3,
@@ -928,10 +947,17 @@ def omen_create_market_tx(
928
947
  # but address of stakingRewardsFactoryAddress on xDai/Gnosis is 0x0000000000000000000000000000000000000000,
929
948
  # so skipping it here.
930
949
 
931
- market_address = create_market_receipt_tx["logs"][-1][
932
- "address"
933
- ] # The market address is available in the last emitted log, in the address field.
934
- return market_address
950
+ return CreatedMarket(
951
+ market_creation_timestamp=get_receipt_block_timestamp(receipt_tx, web3),
952
+ market_event=market_event,
953
+ funding_event=funding_event,
954
+ condition_id=condition_id,
955
+ question_event=question_event,
956
+ condition_event=cond_event,
957
+ initial_funds=initial_funds_wei,
958
+ fee=fee,
959
+ distribution_hint=distribution_hint,
960
+ )
935
961
 
936
962
 
937
963
  def omen_fund_market_tx(
@@ -960,10 +986,6 @@ def omen_fund_market_tx(
960
986
  market_contract.addFunding(api_keys, amount_to_fund, web3=web3)
961
987
 
962
988
 
963
- def build_parent_collection_id() -> HexStr:
964
- return HASH_ZERO # Taken from Olas
965
-
966
-
967
989
  def omen_redeem_full_position_tx(
968
990
  api_keys: APIKeys,
969
991
  market: OmenAgentMarket,
@@ -985,8 +1007,6 @@ def omen_redeem_full_position_tx(
985
1007
  f"Market {market.id} uses conditional token that we didn't expect, {market_contract.conditionalTokens()} != {conditional_token_contract.address=}"
986
1008
  )
987
1009
 
988
- parent_collection_id = build_parent_collection_id()
989
-
990
1010
  if not market.is_resolved():
991
1011
  logger.debug("Cannot redeem winnings if market is not yet resolved. Exiting.")
992
1012
  return
@@ -1007,7 +1027,6 @@ def omen_redeem_full_position_tx(
1007
1027
  api_keys=api_keys,
1008
1028
  collateral_token_address=market.collateral_token_contract_address_checksummed,
1009
1029
  condition_id=market.condition.id,
1010
- parent_collection_id=parent_collection_id,
1011
1030
  index_sets=market.condition.index_sets,
1012
1031
  web3=web3,
1013
1032
  )
@@ -1142,7 +1161,6 @@ def redeem_from_all_user_positions(
1142
1161
  api_keys=api_keys,
1143
1162
  collateral_token_address=user_position.position.collateral_token_contract_address_checksummed,
1144
1163
  condition_id=condition_id,
1145
- parent_collection_id=build_parent_collection_id(),
1146
1164
  index_sets=user_position.position.indexSets,
1147
1165
  web3=web3,
1148
1166
  )