afp-sdk 0.4.0__py3-none-any.whl → 0.5.0__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.
@@ -1,5 +1,6 @@
1
1
  from decimal import Decimal
2
2
  from functools import cache
3
+ from typing import Iterable
3
4
 
4
5
  from eth_typing.evm import ChecksumAddress
5
6
  from hexbytes import HexBytes
@@ -8,10 +9,12 @@ from web3.exceptions import ContractCustomError
8
9
 
9
10
  from .. import validators
10
11
  from ..bindings import (
12
+ BidData,
11
13
  ClearingDiamond,
12
- MarginAccount,
14
+ MarginAccount as MarginContract,
13
15
  MarginAccountRegistry,
14
16
  ProductRegistry,
17
+ Side as OnChainOrderSide,
15
18
  )
16
19
  from ..bindings.erc20 import ERC20
17
20
  from ..bindings.facade import CLEARING_DIAMOND_ABI
@@ -20,26 +23,41 @@ from ..bindings.margin_account_registry import ABI as MARGIN_ACCOUNT_REGISTRY_AB
20
23
  from ..bindings.product_registry import ABI as PRODUCT_REGISTRY_ABI
21
24
  from ..decorators import convert_web3_error
22
25
  from ..exceptions import NotFoundError
23
- from ..schemas import Position
26
+ from ..schemas import AuctionData, Bid, OrderSide, Position, Transaction
24
27
  from .base import ClearingSystemAPI
25
- from .builder import Builder
26
28
 
27
29
 
28
- class Clearing(ClearingSystemAPI):
29
- """API for managing margin accounts.
30
+ class MarginAccount(ClearingSystemAPI):
31
+ """API for managing margin accounts."""
30
32
 
31
- Parameters
32
- ----------
33
- private_key : str
34
- The private key of the blockchain account that manages the margin account.
35
- autonity_rpc_url : str
36
- The URL of a JSON-RPC provider for Autonity. (HTTPS only.)
37
- """
33
+ ### Factories ###
34
+
35
+ @staticmethod
36
+ def create_bid(product_id: str, price: Decimal, quantity: int, side: str) -> Bid:
37
+ """Create a bid to be submitted to a liquidation auction.
38
+
39
+ Parameters
40
+ ----------
41
+ product_id : str
42
+ price: Decimal
43
+ quantity: int
44
+ side: str
45
+
46
+ Returns
47
+ -------
48
+ afp.schemas.Bid
49
+ """
50
+ return Bid(
51
+ product_id=product_id,
52
+ price=price,
53
+ quantity=quantity,
54
+ side=getattr(OrderSide, side.upper()),
55
+ )
38
56
 
39
57
  ### Transactions ###
40
58
 
41
59
  @convert_web3_error(MARGIN_CONTRACT_ABI)
42
- def authorize(self, collateral_asset: str, intent_account_id: str) -> str:
60
+ def authorize(self, collateral_asset: str, intent_account_id: str) -> Transaction:
43
61
  """Authorizes a blockchain account to submit intents to the clearing system
44
62
  using the margin account associated with the collateral asset.
45
63
 
@@ -52,24 +70,19 @@ class Clearing(ClearingSystemAPI):
52
70
 
53
71
  Returns
54
72
  -------
55
- str
56
- The hash of the transaction.
73
+ afp.schemas.Transaction
74
+ Transaction parameters.
57
75
  """
58
76
  collateral_asset = validators.validate_address(collateral_asset)
59
77
  intent_account_id = validators.validate_address(intent_account_id)
60
-
61
- tx_hash = (
62
- self._margin_contract(collateral_asset)
63
- .authorize(intent_account_id)
64
- .transact()
78
+ return self._transact(
79
+ self._margin_contract(collateral_asset).authorize(intent_account_id)
65
80
  )
66
- self._w3.eth.wait_for_transaction_receipt(tx_hash)
67
- return Web3.to_hex(tx_hash)
68
81
 
69
82
  @convert_web3_error(MARGIN_CONTRACT_ABI)
70
- def deposit_into_margin_account(
83
+ def deposit(
71
84
  self, collateral_asset: str, amount: Decimal
72
- ) -> tuple[str, str]:
85
+ ) -> tuple[Transaction, Transaction]:
73
86
  """Deposits the specified amount of collateral tokens into the margin account
74
87
  associated with the collateral asset.
75
88
 
@@ -85,32 +98,28 @@ class Clearing(ClearingSystemAPI):
85
98
 
86
99
  Returns
87
100
  -------
88
- str
89
- The hash of the approval transaction.
90
- str
91
- The hash of the deposit transaction.
101
+ afp.schemas.Transaction
102
+ Parameters of the approval transaction.
103
+ afp.schemas.Transaction
104
+ Parameters of the deposit transaction.
92
105
  """
93
106
  collateral_asset = validators.validate_address(collateral_asset)
94
107
  token_amount = int(amount * 10 ** self._decimals(collateral_asset))
95
108
  token_contract = ERC20(self._w3, collateral_asset)
96
109
 
97
- tx1_hash = token_contract.approve(
98
- self._margin_contract(collateral_asset)._contract.address, # type: ignore
99
- token_amount,
100
- ).transact()
101
- self._w3.eth.wait_for_transaction_receipt(tx1_hash)
102
-
103
- tx2_hash = (
104
- self._margin_contract(collateral_asset).deposit(token_amount).transact()
110
+ tx1 = self._transact(
111
+ token_contract.approve(
112
+ self._margin_contract(collateral_asset)._contract.address, # type: ignore
113
+ token_amount,
114
+ )
105
115
  )
106
- self._w3.eth.wait_for_transaction_receipt(tx2_hash)
107
-
108
- return (Web3.to_hex(tx1_hash), Web3.to_hex(tx2_hash))
116
+ tx2 = self._transact(
117
+ self._margin_contract(collateral_asset).deposit(token_amount)
118
+ )
119
+ return (tx1, tx2)
109
120
 
110
121
  @convert_web3_error(MARGIN_CONTRACT_ABI)
111
- def withdraw_from_margin_account(
112
- self, collateral_asset: str, amount: Decimal
113
- ) -> str:
122
+ def withdraw(self, collateral_asset: str, amount: Decimal) -> Transaction:
114
123
  """Withdraws the specified amount of collateral tokens from the margin account
115
124
  associated with the collateral asset.
116
125
 
@@ -123,46 +132,83 @@ class Clearing(ClearingSystemAPI):
123
132
 
124
133
  Returns
125
134
  -------
126
- str
127
- The hash of the transaction.
135
+ afp.schemas.Transaction
136
+ Transaction parameters.
128
137
  """
129
138
  collateral_asset = validators.validate_address(collateral_asset)
130
139
  token_amount = int(amount * 10 ** self._decimals(collateral_asset))
131
- tx_hash = (
132
- self._margin_contract(collateral_asset).withdraw(token_amount).transact()
140
+ return self._transact(
141
+ self._margin_contract(collateral_asset).withdraw(token_amount)
133
142
  )
134
- self._w3.eth.wait_for_transaction_receipt(tx_hash)
135
- return Web3.to_hex(tx_hash)
136
143
 
137
144
  @convert_web3_error(CLEARING_DIAMOND_ABI)
138
- def initiate_final_settlement(self, product_id: str, accounts: list[str]) -> str:
139
- """Initiate final settlement (closeout) process for the specified accounts.
145
+ def request_liquidation(
146
+ self, margin_account_id: str, collateral_asset: str
147
+ ) -> Transaction:
148
+ """Request a liquidation auction to be started.
140
149
 
141
- The product must be in Final Settlement state. The accounts must hold non-zero
142
- positions in the product that offset each other (i.e. the sum of their position
143
- sizes is 0.)
150
+ Parameters
151
+ ----------
152
+ margin_account_id : str
153
+ The ID of the margin account to be liquidated.
154
+ collateral_asset : str
155
+ The address of the collateral token that the margin account is trading with.
156
+
157
+ Returns
158
+ -------
159
+ afp.schemas.Transaction
160
+ Transaction parameters.
161
+ """
162
+ margin_account_id = validators.validate_address(margin_account_id)
163
+ collateral_asset = validators.validate_address(collateral_asset)
164
+
165
+ clearing_contract = ClearingDiamond(
166
+ self._w3, self._config.clearing_diamond_address
167
+ )
168
+ return self._transact(
169
+ clearing_contract.request_liquidation(margin_account_id, collateral_asset)
170
+ )
171
+
172
+ @convert_web3_error(CLEARING_DIAMOND_ABI, PRODUCT_REGISTRY_ABI)
173
+ def submit_bids(
174
+ self, margin_account_id: str, collateral_asset: str, bids: Iterable[Bid]
175
+ ) -> Transaction:
176
+ """Submit bids to a liquidation auction.
144
177
 
145
178
  Parameters
146
179
  ----------
147
- product_id : str
148
- The ID of the product.
149
- accounts : list of str
150
- List of margin account IDs to initiate settlement for.
180
+ margin_account_id : str
181
+ The ID of the margin account that is being liquidated.
182
+ collateral_asset : str
183
+ The address of the collateral token that the margin account is trading with.
184
+ bids: list of afp.schemas.Bid
151
185
 
152
186
  Returns
153
187
  -------
154
- str
155
- The hash of the transaction.
188
+ afp.schemas.Transaction
189
+ Transaction parameters.
156
190
  """
157
- product_id = validators.validate_hexstr32(product_id)
158
- addresses = [validators.validate_address(account) for account in accounts]
191
+ margin_account_id = validators.validate_address(margin_account_id)
192
+ collateral_asset = validators.validate_address(collateral_asset)
159
193
 
160
- clearing_contract = ClearingDiamond(self._w3)
161
- tx_hash = clearing_contract.initiate_final_settlement(
162
- HexBytes(product_id), addresses
163
- ).transact()
164
- self._w3.eth.wait_for_transaction_receipt(tx_hash)
165
- return Web3.to_hex(tx_hash)
194
+ converted_bids = [
195
+ BidData(
196
+ product_id=HexBytes(bid.product_id),
197
+ price=int(bid.price * 10 ** self._tick_size(bid.product_id)),
198
+ quantity=bid.quantity,
199
+ side=getattr(OnChainOrderSide, bid.side.name),
200
+ )
201
+ for bid in bids
202
+ ]
203
+
204
+ clearing_contract = ClearingDiamond(
205
+ self._w3, self._config.clearing_diamond_address
206
+ )
207
+ return self._transact(
208
+ clearing_contract.bid_auction(
209
+ margin_account_id, collateral_asset, converted_bids
210
+ )
211
+ )
166
212
 
167
213
  ### Views ###
168
214
 
@@ -181,7 +227,9 @@ class Clearing(ClearingSystemAPI):
181
227
  Decimal
182
228
  """
183
229
  collateral_asset = validators.validate_address(collateral_asset)
184
- amount = self._margin_contract(collateral_asset).capital(self._account.address)
230
+ amount = self._margin_contract(collateral_asset).capital(
231
+ self._authenticator.address
232
+ )
185
233
  return Decimal(amount) / 10 ** self._decimals(collateral_asset)
186
234
 
187
235
  @convert_web3_error(MARGIN_CONTRACT_ABI)
@@ -202,7 +250,7 @@ class Clearing(ClearingSystemAPI):
202
250
  """
203
251
  validators.validate_hexstr32(position_id)
204
252
  data = self._margin_contract(collateral_asset).position_data(
205
- self._account.address, HexBytes(position_id)
253
+ self._authenticator.address, HexBytes(position_id)
206
254
  )
207
255
  decimals = self._decimals(collateral_asset)
208
256
  return Position(
@@ -229,12 +277,12 @@ class Clearing(ClearingSystemAPI):
229
277
  """
230
278
  collateral_asset = validators.validate_address(collateral_asset)
231
279
  position_ids = self._margin_contract(collateral_asset).positions(
232
- self._account.address
280
+ self._authenticator.address
233
281
  )
234
282
  return [self.position(collateral_asset, Web3.to_hex(id)) for id in position_ids]
235
283
 
236
284
  @convert_web3_error(MARGIN_CONTRACT_ABI)
237
- def margin_account_equity(self, collateral_asset: str) -> Decimal:
285
+ def equity(self, collateral_asset: str) -> Decimal:
238
286
  """Returns the margin account equity in the margin account associated with the
239
287
  collateral asset.
240
288
 
@@ -248,7 +296,9 @@ class Clearing(ClearingSystemAPI):
248
296
  Decimal
249
297
  """
250
298
  collateral_asset = validators.validate_address(collateral_asset)
251
- amount = self._margin_contract(collateral_asset).mae(self._account.address)
299
+ amount = self._margin_contract(collateral_asset).mae(
300
+ self._authenticator.address
301
+ )
252
302
  return Decimal(amount) / 10 ** self._decimals(collateral_asset)
253
303
 
254
304
  @convert_web3_error(MARGIN_CONTRACT_ABI)
@@ -266,7 +316,9 @@ class Clearing(ClearingSystemAPI):
266
316
  Decimal
267
317
  """
268
318
  collateral_asset = validators.validate_address(collateral_asset)
269
- amount = self._margin_contract(collateral_asset).mma(self._account.address)
319
+ amount = self._margin_contract(collateral_asset).mma(
320
+ self._authenticator.address
321
+ )
270
322
  return Decimal(amount) / 10 ** self._decimals(collateral_asset)
271
323
 
272
324
  @convert_web3_error(MARGIN_CONTRACT_ABI)
@@ -284,7 +336,9 @@ class Clearing(ClearingSystemAPI):
284
336
  Decimal
285
337
  """
286
338
  collateral_asset = validators.validate_address(collateral_asset)
287
- amount = self._margin_contract(collateral_asset).mmu(self._account.address)
339
+ amount = self._margin_contract(collateral_asset).mmu(
340
+ self._authenticator.address
341
+ )
288
342
  return Decimal(amount) / 10 ** self._decimals(collateral_asset)
289
343
 
290
344
  @convert_web3_error(MARGIN_CONTRACT_ABI)
@@ -302,7 +356,9 @@ class Clearing(ClearingSystemAPI):
302
356
  Decimal
303
357
  """
304
358
  collateral_asset = validators.validate_address(collateral_asset)
305
- amount = self._margin_contract(collateral_asset).pnl(self._account.address)
359
+ amount = self._margin_contract(collateral_asset).pnl(
360
+ self._authenticator.address
361
+ )
306
362
  return Decimal(amount) / 10 ** self._decimals(collateral_asset)
307
363
 
308
364
  @convert_web3_error(MARGIN_CONTRACT_ABI)
@@ -321,51 +377,56 @@ class Clearing(ClearingSystemAPI):
321
377
  """
322
378
  collateral_asset = validators.validate_address(collateral_asset)
323
379
  amount = self._margin_contract(collateral_asset).withdrawable(
324
- self._account.address
380
+ self._authenticator.address
325
381
  )
326
382
  return Decimal(amount) / 10 ** self._decimals(collateral_asset)
327
383
 
328
- @convert_web3_error(PRODUCT_REGISTRY_ABI)
329
- def collateral_asset(self, product_id: str) -> str:
330
- """Returns the collateral asset of a product.
384
+ @convert_web3_error(CLEARING_DIAMOND_ABI)
385
+ def auction_data(
386
+ self, margin_account_id: str, collateral_asset: str
387
+ ) -> AuctionData:
388
+ """Returns information on a liquidation auction.
331
389
 
332
390
  Parameters
333
391
  ----------
334
- product_id : str
335
- The ID of the product.
392
+ margin_account_id : str
393
+ The ID of the margin account to be liquidated.
394
+ collateral_asset : str
395
+ The address of the collateral token that the margin account is trading with.
336
396
 
337
397
  Returns
338
398
  -------
339
399
  str
400
+ The hash of the transaction.
340
401
  """
341
- product_registry_contract = ProductRegistry(self._w3)
342
- collateral_asset = product_registry_contract.collateral_asset(
343
- HexBytes(product_id)
344
- )
345
- if Web3.to_int(hexstr=collateral_asset) == 0:
346
- raise NotFoundError("Product not found in the product registry")
347
- return collateral_asset
348
-
349
- def product_state(self, product_id: str) -> str:
350
- """Returns the current state of a product.
351
-
352
- Parameters
353
- ----------
354
- product_id : str
355
- The ID of the product.
402
+ margin_account_id = validators.validate_address(margin_account_id)
403
+ collateral_asset = validators.validate_address(collateral_asset)
356
404
 
357
- Returns
358
- -------
359
- str
360
- """
361
- return Builder.product_state(self, product_id)
405
+ clearing_contract = ClearingDiamond(
406
+ self._w3, self._config.clearing_diamond_address
407
+ )
408
+ data = clearing_contract.auction_data(margin_account_id, collateral_asset)
409
+ divisor = 10 ** self._decimals(collateral_asset)
410
+ return AuctionData(
411
+ start_block=data.start_block,
412
+ margin_account_equity_at_initiation=(
413
+ Decimal(data.mae_at_initiation) / divisor
414
+ ),
415
+ maintenance_margin_used_at_initiation=(
416
+ Decimal(data.mmu_at_initiation) / divisor
417
+ ),
418
+ margin_account_equity_now=(Decimal(data.mae_now) / divisor),
419
+ maintenance_margin_used_now=(Decimal(data.mmu_now) / divisor),
420
+ )
362
421
 
363
422
  ### Internal getters ###
364
423
 
365
424
  @cache
366
425
  @convert_web3_error(MARGIN_ACCOUNT_REGISTRY_ABI)
367
- def _margin_contract(self, collateral_asset: ChecksumAddress) -> MarginAccount:
368
- margin_account_registry_contract = MarginAccountRegistry(self._w3)
426
+ def _margin_contract(self, collateral_asset: ChecksumAddress) -> MarginContract:
427
+ margin_account_registry_contract = MarginAccountRegistry(
428
+ self._w3, self._config.margin_account_registry_address
429
+ )
369
430
  try:
370
431
  margin_contract_address = (
371
432
  margin_account_registry_contract.get_margin_account(
@@ -374,4 +435,11 @@ class Clearing(ClearingSystemAPI):
374
435
  )
375
436
  except ContractCustomError:
376
437
  raise NotFoundError("No margin account found for collateral asset")
377
- return MarginAccount(self._w3, margin_contract_address)
438
+ return MarginContract(self._w3, margin_contract_address)
439
+
440
+ @cache
441
+ def _tick_size(self, product_id: str) -> int:
442
+ product_registry_contract = ProductRegistry(
443
+ self._w3, self._config.product_registry_address
444
+ )
445
+ return product_registry_contract.tick_size(HexBytes(product_id))
@@ -6,31 +6,27 @@ from eth_typing.evm import ChecksumAddress
6
6
  from hexbytes import HexBytes
7
7
  from web3 import Web3
8
8
 
9
- from .. import config, signing, validators
9
+ from .. import constants, hashing, validators
10
10
  from ..bindings import (
11
+ ClearingDiamond,
11
12
  OracleSpecification,
12
- Product,
13
+ Product as OnChainProduct,
13
14
  ProductMetadata,
14
15
  ProductRegistry,
15
16
  )
16
17
  from ..bindings.erc20 import ERC20
18
+ from ..bindings.facade import CLEARING_DIAMOND_ABI
17
19
  from ..bindings.product_registry import ABI as PRODUCT_REGISTRY_ABI
18
20
  from ..decorators import convert_web3_error
19
21
  from ..exceptions import NotFoundError
20
- from ..schemas import ProductSpecification
22
+ from ..schemas import ProductSpecification, Transaction
21
23
  from .base import ClearingSystemAPI
22
24
 
23
25
 
24
- class Builder(ClearingSystemAPI):
25
- """API for building and submitting new products.
26
+ class Product(ClearingSystemAPI):
27
+ """API for managing products."""
26
28
 
27
- Parameters
28
- ----------
29
- private_key : str
30
- The private key of the blockchain account that submits the product.
31
- autonity_rpc_url : str
32
- The URL of a JSON-RPC provider for Autonity. (HTTPS only.)
33
- """
29
+ ### Factories ###
34
30
 
35
31
  @convert_web3_error()
36
32
  def create_product(
@@ -38,7 +34,6 @@ class Builder(ClearingSystemAPI):
38
34
  *,
39
35
  symbol: str,
40
36
  description: str,
41
- oracle_address: str,
42
37
  fsv_decimals: int,
43
38
  fsp_alpha: Decimal,
44
39
  fsp_beta: Decimal,
@@ -53,6 +48,7 @@ class Builder(ClearingSystemAPI):
53
48
  auction_bounty: Decimal,
54
49
  tradeout_interval: int,
55
50
  extended_metadata: str,
51
+ oracle_address: str | None = None,
56
52
  ) -> ProductSpecification:
57
53
  """Creates a product specification with the given product data.
58
54
 
@@ -63,7 +59,6 @@ class Builder(ClearingSystemAPI):
63
59
  ----------
64
60
  symbol : str
65
61
  description : str
66
- oracle_address: str
67
62
  fsv_decimals: int
68
63
  fsp_alpha: Decimal
69
64
  fsp_beta: int
@@ -78,25 +73,30 @@ class Builder(ClearingSystemAPI):
78
73
  auction_bounty : Decimal
79
74
  tradeout_interval : int
80
75
  extended_metadata : str
76
+ oracle_address: str, optional
81
77
 
82
78
  Returns
83
79
  -------
84
80
  afp.schemas.ProductSpecification
85
81
  """
86
- product_id = Web3.to_hex(signing.generate_product_id(self._account, symbol))
82
+ if oracle_address is None:
83
+ oracle_address = self._config.oracle_provider_address
87
84
 
88
- erc20_contract = ERC20(self._w3, Web3.to_checksum_address(collateral_asset))
89
- price_quotation = erc20_contract.symbol()
90
-
91
- if not price_quotation:
85
+ if len(self._w3.eth.get_code(Web3.to_checksum_address(collateral_asset))) == 0:
92
86
  raise NotFoundError(f"No ERC20 token found at address {collateral_asset}")
93
-
94
87
  if len(self._w3.eth.get_code(Web3.to_checksum_address(oracle_address))) == 0:
95
88
  raise NotFoundError(f"No contract found at oracle address {oracle_address}")
96
89
 
90
+ erc20_contract = ERC20(self._w3, Web3.to_checksum_address(collateral_asset))
91
+ price_quotation = erc20_contract.symbol()
92
+
93
+ product_id = Web3.to_hex(
94
+ hashing.generate_product_id(self._authenticator.address, symbol)
95
+ )
96
+
97
97
  return ProductSpecification(
98
98
  id=product_id,
99
- builder_id=self._account.address,
99
+ builder_id=self._authenticator.address,
100
100
  symbol=symbol,
101
101
  description=description,
102
102
  oracle_address=oracle_address,
@@ -117,8 +117,10 @@ class Builder(ClearingSystemAPI):
117
117
  extended_metadata=extended_metadata,
118
118
  )
119
119
 
120
+ ### Transactions ###
121
+
120
122
  @convert_web3_error(PRODUCT_REGISTRY_ABI)
121
- def register_product(self, product: ProductSpecification) -> str:
123
+ def register_product(self, product: ProductSpecification) -> Transaction:
122
124
  """Submits a product specification to the clearing system.
123
125
 
124
126
  Parameters
@@ -127,20 +129,56 @@ class Builder(ClearingSystemAPI):
127
129
 
128
130
  Returns
129
131
  -------
130
- str
131
- The hash of the transaction.
132
+ afp.schemas.Transaction
133
+ Transaction parameters.
132
134
  """
133
135
  erc20_contract = ERC20(
134
136
  self._w3, cast(ChecksumAddress, product.collateral_asset)
135
137
  )
136
138
  decimals = erc20_contract.decimals()
137
139
 
138
- product_registry_contract = ProductRegistry(self._w3)
139
- tx_hash = product_registry_contract.register(
140
- self._convert_product_specification(product, decimals)
141
- ).transact()
142
- self._w3.eth.wait_for_transaction_receipt(tx_hash)
143
- return Web3.to_hex(tx_hash)
140
+ product_registry_contract = ProductRegistry(
141
+ self._w3, self._config.product_registry_address
142
+ )
143
+ return self._transact(
144
+ product_registry_contract.register(
145
+ self._convert_product_specification(product, decimals)
146
+ )
147
+ )
148
+
149
+ @convert_web3_error(CLEARING_DIAMOND_ABI)
150
+ def initiate_final_settlement(
151
+ self, product_id: str, accounts: list[str]
152
+ ) -> Transaction:
153
+ """Initiate final settlement (closeout) process for the specified accounts.
154
+
155
+ The product must be in Final Settlement state. The accounts must hold non-zero
156
+ positions in the product that offset each other (i.e. the sum of their position
157
+ sizes is 0.)
158
+
159
+ Parameters
160
+ ----------
161
+ product_id : str
162
+ The ID of the product.
163
+ accounts : list of str
164
+ List of margin account IDs to initiate settlement for.
165
+
166
+ Returns
167
+ -------
168
+ afp.schemas.Transaction
169
+ Transaction parameters.
170
+ """
171
+ product_id = validators.validate_hexstr32(product_id)
172
+ addresses = [validators.validate_address(account) for account in accounts]
173
+
174
+ clearing_contract = ClearingDiamond(
175
+ self._w3, self._config.clearing_diamond_address
176
+ )
177
+ return self._transact(
178
+ clearing_contract.initiate_final_settlement(HexBytes(product_id), addresses)
179
+ )
180
+
181
+ ### Views ###
144
182
 
145
183
  @convert_web3_error(PRODUCT_REGISTRY_ABI)
146
184
  def product_state(self, product_id: str) -> str:
@@ -156,15 +194,43 @@ class Builder(ClearingSystemAPI):
156
194
  str
157
195
  """
158
196
  product_id = validators.validate_hexstr32(product_id)
159
- product_registry_contract = ProductRegistry(self._w3)
197
+ product_registry_contract = ProductRegistry(
198
+ self._w3, self._config.product_registry_address
199
+ )
160
200
  state = product_registry_contract.state(HexBytes(product_id))
161
201
  return state.name
162
202
 
203
+ @convert_web3_error(PRODUCT_REGISTRY_ABI)
204
+ def collateral_asset(self, product_id: str) -> str:
205
+ """Returns the collateral asset of a product.
206
+
207
+ Parameters
208
+ ----------
209
+ product_id : str
210
+ The ID of the product.
211
+
212
+ Returns
213
+ -------
214
+ str
215
+ """
216
+ product_id = validators.validate_hexstr32(product_id)
217
+ product_registry_contract = ProductRegistry(
218
+ self._w3, self._config.product_registry_address
219
+ )
220
+ collateral_asset = product_registry_contract.collateral_asset(
221
+ HexBytes(product_id)
222
+ )
223
+ if Web3.to_int(hexstr=collateral_asset) == 0:
224
+ raise NotFoundError("Product not found in the product registry")
225
+ return collateral_asset
226
+
227
+ ### Internal helpers ###
228
+
163
229
  @staticmethod
164
230
  def _convert_product_specification(
165
231
  product: ProductSpecification, decimals: int
166
- ) -> Product:
167
- return Product(
232
+ ) -> OnChainProduct:
233
+ return OnChainProduct(
168
234
  metadata=ProductMetadata(
169
235
  builder=cast(ChecksumAddress, product.builder_id),
170
236
  symbol=product.symbol,
@@ -173,7 +239,7 @@ class Builder(ClearingSystemAPI):
173
239
  oracle_spec=OracleSpecification(
174
240
  oracle_address=cast(ChecksumAddress, product.oracle_address),
175
241
  fsv_decimals=product.fsv_decimals,
176
- fsp_alpha=int(product.fsp_alpha * config.FULL_PRECISION_MULTIPLIER),
242
+ fsp_alpha=int(product.fsp_alpha * constants.FULL_PRECISION_MULTIPLIER),
177
243
  fsp_beta=int(product.fsp_beta * 10**product.fsv_decimals),
178
244
  fsv_calldata=HexBytes(product.fsv_calldata),
179
245
  ),
@@ -186,12 +252,12 @@ class Builder(ClearingSystemAPI):
186
252
  tick_size=product.tick_size,
187
253
  unit_value=int(product.unit_value * 10**decimals),
188
254
  initial_margin_requirement=int(
189
- product.initial_margin_requirement * config.RATE_MULTIPLIER
255
+ product.initial_margin_requirement * constants.RATE_MULTIPLIER
190
256
  ),
191
257
  maintenance_margin_requirement=int(
192
- product.maintenance_margin_requirement * config.RATE_MULTIPLIER
258
+ product.maintenance_margin_requirement * constants.RATE_MULTIPLIER
193
259
  ),
194
- auction_bounty=int(product.auction_bounty * config.RATE_MULTIPLIER),
260
+ auction_bounty=int(product.auction_bounty * constants.RATE_MULTIPLIER),
195
261
  tradeout_interval=product.tradeout_interval,
196
262
  extended_metadata=product.extended_metadata,
197
263
  )