nado-protocol 0.3.1__py3-none-any.whl → 0.3.3__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.
- nado_protocol/client/__init__.py +1 -0
- nado_protocol/contracts/__init__.py +73 -1
- nado_protocol/contracts/abis/IOffchainExchange.json +43 -0
- nado_protocol/contracts/deployments/deployment.mainnet.json +1 -0
- nado_protocol/contracts/deployments/deployment.testing.json +1 -0
- nado_protocol/contracts/deployments/deployment.testnet.json +1 -0
- nado_protocol/contracts/types.py +34 -0
- nado_protocol/indexer_client/types/models.py +5 -2
- nado_protocol/utils/__init__.py +8 -0
- nado_protocol/utils/order.py +83 -4
- nado_protocol/utils/slow_mode.py +48 -0
- {nado_protocol-0.3.1.dist-info → nado_protocol-0.3.3.dist-info}/METADATA +1 -1
- {nado_protocol-0.3.1.dist-info → nado_protocol-0.3.3.dist-info}/RECORD +15 -13
- {nado_protocol-0.3.1.dist-info → nado_protocol-0.3.3.dist-info}/WHEEL +1 -1
- {nado_protocol-0.3.1.dist-info → nado_protocol-0.3.3.dist-info}/entry_points.txt +1 -0
nado_protocol/client/__init__.py
CHANGED
|
@@ -133,6 +133,7 @@ def create_nado_client(
|
|
|
133
133
|
perp_engine_addr=deployment.perp_engine_addr,
|
|
134
134
|
spot_engine_addr=deployment.spot_engine_addr,
|
|
135
135
|
clearinghouse_addr=deployment.clearinghouse_addr,
|
|
136
|
+
offchain_exchange_addr=deployment.offchain_exchange_addr,
|
|
136
137
|
airdrop_addr=deployment.airdrop_addr,
|
|
137
138
|
staking_addr=deployment.staking_addr,
|
|
138
139
|
foundation_rewards_airdrop_addr=deployment.foundation_rewards_airdrop_addr,
|
|
@@ -7,14 +7,21 @@ from web3.contract import Contract
|
|
|
7
7
|
from web3.contract.contract import ContractFunction
|
|
8
8
|
from eth_account.signers.local import LocalAccount
|
|
9
9
|
from nado_protocol.contracts.loader import load_abi
|
|
10
|
-
from nado_protocol.contracts.types import
|
|
10
|
+
from nado_protocol.contracts.types import (
|
|
11
|
+
BuilderInfo,
|
|
12
|
+
ClaimBuilderFeeParams,
|
|
13
|
+
DepositCollateralParams,
|
|
14
|
+
NadoAbiName,
|
|
15
|
+
)
|
|
11
16
|
from nado_protocol.utils.bytes32 import (
|
|
12
17
|
hex_to_bytes32,
|
|
13
18
|
str_to_hex,
|
|
14
19
|
subaccount_name_to_bytes12,
|
|
20
|
+
subaccount_to_bytes32,
|
|
15
21
|
zero_address,
|
|
16
22
|
)
|
|
17
23
|
from nado_protocol.utils.exceptions import InvalidProductId
|
|
24
|
+
from nado_protocol.utils.slow_mode import encode_claim_builder_fee_tx
|
|
18
25
|
from nado_protocol.contracts.types import *
|
|
19
26
|
|
|
20
27
|
|
|
@@ -33,6 +40,8 @@ class NadoContractsContext(BaseModel):
|
|
|
33
40
|
|
|
34
41
|
clearinghouse_addr (Optional[str]): The clearinghouse address. This may be None.
|
|
35
42
|
|
|
43
|
+
offchain_exchange_addr (Optional[str]): The offchain exchange address. This may be None.
|
|
44
|
+
|
|
36
45
|
airdrop_addr (Optional[str]): The airdrop address. This may be None.
|
|
37
46
|
|
|
38
47
|
staking_addr (Optional[str]): The staking address. This may be None.
|
|
@@ -46,6 +55,7 @@ class NadoContractsContext(BaseModel):
|
|
|
46
55
|
spot_engine_addr: Optional[str]
|
|
47
56
|
perp_engine_addr: Optional[str]
|
|
48
57
|
clearinghouse_addr: Optional[str]
|
|
58
|
+
offchain_exchange_addr: Optional[str]
|
|
49
59
|
airdrop_addr: Optional[str]
|
|
50
60
|
staking_addr: Optional[str]
|
|
51
61
|
foundation_rewards_airdrop_addr: Optional[str]
|
|
@@ -62,6 +72,7 @@ class NadoContracts:
|
|
|
62
72
|
querier: Contract
|
|
63
73
|
endpoint: Contract
|
|
64
74
|
clearinghouse: Optional[Contract]
|
|
75
|
+
offchain_exchange: Optional[Contract]
|
|
65
76
|
spot_engine: Optional[Contract]
|
|
66
77
|
perp_engine: Optional[Contract]
|
|
67
78
|
airdrop: Optional[Contract]
|
|
@@ -92,6 +103,7 @@ class NadoContracts:
|
|
|
92
103
|
abi=load_abi(NadoAbiName.ENDPOINT), # type: ignore
|
|
93
104
|
)
|
|
94
105
|
self.clearinghouse = None
|
|
106
|
+
self.offchain_exchange = None
|
|
95
107
|
self.spot_engine = None
|
|
96
108
|
self.perp_engine = None
|
|
97
109
|
|
|
@@ -113,6 +125,12 @@ class NadoContracts:
|
|
|
113
125
|
abi=load_abi(NadoAbiName.IPERP_ENGINE), # type: ignore
|
|
114
126
|
)
|
|
115
127
|
|
|
128
|
+
if self.contracts_context.offchain_exchange_addr:
|
|
129
|
+
self.offchain_exchange: Contract = self.w3.eth.contract(
|
|
130
|
+
address=self.contracts_context.offchain_exchange_addr,
|
|
131
|
+
abi=load_abi(NadoAbiName.IOFFCHAIN_EXCHANGE), # type: ignore
|
|
132
|
+
)
|
|
133
|
+
|
|
116
134
|
if self.contracts_context.staking_addr:
|
|
117
135
|
self.staking: Contract = self.w3.eth.contract(
|
|
118
136
|
address=self.contracts_context.staking_addr,
|
|
@@ -294,6 +312,58 @@ class NadoContracts:
|
|
|
294
312
|
self.foundation_rewards_airdrop.functions.claim(proofs), signer
|
|
295
313
|
)
|
|
296
314
|
|
|
315
|
+
def claim_builder_fee(
|
|
316
|
+
self,
|
|
317
|
+
params: ClaimBuilderFeeParams,
|
|
318
|
+
signer: LocalAccount,
|
|
319
|
+
) -> str:
|
|
320
|
+
"""
|
|
321
|
+
Claims accumulated builder fees via slow mode transaction.
|
|
322
|
+
|
|
323
|
+
This submits a ClaimBuilderFee slow mode transaction to the Endpoint contract.
|
|
324
|
+
The fees will be credited to the specified subaccount.
|
|
325
|
+
|
|
326
|
+
Args:
|
|
327
|
+
params (ClaimBuilderFeeParams): The parameters for claiming builder fees.
|
|
328
|
+
signer (LocalAccount): The account that will sign the transaction.
|
|
329
|
+
|
|
330
|
+
Returns:
|
|
331
|
+
str: The transaction hash of the claim operation.
|
|
332
|
+
"""
|
|
333
|
+
params = ClaimBuilderFeeParams.parse_obj(params)
|
|
334
|
+
sender_bytes = subaccount_to_bytes32(
|
|
335
|
+
params.subaccount_owner, params.subaccount_name
|
|
336
|
+
)
|
|
337
|
+
tx_bytes = encode_claim_builder_fee_tx(sender_bytes, params.builder_id)
|
|
338
|
+
return self.execute(
|
|
339
|
+
self.endpoint.functions.submitSlowModeTransaction(tx_bytes),
|
|
340
|
+
signer,
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
def get_builder_info(self, builder_id: int) -> BuilderInfo:
|
|
344
|
+
"""
|
|
345
|
+
Gets builder information from the OffchainExchange contract.
|
|
346
|
+
|
|
347
|
+
Args:
|
|
348
|
+
builder_id (int): The builder ID to query.
|
|
349
|
+
|
|
350
|
+
Returns:
|
|
351
|
+
BuilderInfo: The builder information including owner, fee tier, and fee rates.
|
|
352
|
+
|
|
353
|
+
Raises:
|
|
354
|
+
Exception: If the OffchainExchange contract is not initialized.
|
|
355
|
+
"""
|
|
356
|
+
if self.offchain_exchange is None:
|
|
357
|
+
raise Exception("OffchainExchange contract not initialized")
|
|
358
|
+
|
|
359
|
+
result = self.offchain_exchange.functions.getBuilder(builder_id).call()
|
|
360
|
+
return BuilderInfo(
|
|
361
|
+
owner=result[0],
|
|
362
|
+
default_fee_tier=result[1],
|
|
363
|
+
lowest_fee_rate=result[2],
|
|
364
|
+
highest_fee_rate=result[3],
|
|
365
|
+
)
|
|
366
|
+
|
|
297
367
|
def _mint_mock_erc20(
|
|
298
368
|
self, erc20: Contract, amount: int, signer: LocalAccount
|
|
299
369
|
) -> str:
|
|
@@ -377,6 +447,8 @@ class NadoContracts:
|
|
|
377
447
|
__all__ = [
|
|
378
448
|
"NadoContractsContext",
|
|
379
449
|
"NadoContracts",
|
|
450
|
+
"BuilderInfo",
|
|
451
|
+
"ClaimBuilderFeeParams",
|
|
380
452
|
"DepositCollateralParams",
|
|
381
453
|
"NadoExecuteType",
|
|
382
454
|
"NadoNetwork",
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"inputs": [
|
|
4
|
+
{
|
|
5
|
+
"internalType": "uint32",
|
|
6
|
+
"name": "builderId",
|
|
7
|
+
"type": "uint32"
|
|
8
|
+
}
|
|
9
|
+
],
|
|
10
|
+
"name": "getBuilder",
|
|
11
|
+
"outputs": [
|
|
12
|
+
{
|
|
13
|
+
"components": [
|
|
14
|
+
{
|
|
15
|
+
"internalType": "address",
|
|
16
|
+
"name": "owner",
|
|
17
|
+
"type": "address"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"internalType": "uint32",
|
|
21
|
+
"name": "defaultFeeTier",
|
|
22
|
+
"type": "uint32"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"internalType": "int128",
|
|
26
|
+
"name": "lowestFeeRate",
|
|
27
|
+
"type": "int128"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"internalType": "int128",
|
|
31
|
+
"name": "highestFeeRate",
|
|
32
|
+
"type": "int128"
|
|
33
|
+
}
|
|
34
|
+
],
|
|
35
|
+
"internalType": "struct IOffchainExchange.Builder",
|
|
36
|
+
"name": "",
|
|
37
|
+
"type": "tuple"
|
|
38
|
+
}
|
|
39
|
+
],
|
|
40
|
+
"stateMutability": "view",
|
|
41
|
+
"type": "function"
|
|
42
|
+
}
|
|
43
|
+
]
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"endpoint": "0x05ec92D78ED421f3D3Ada77FFdE167106565974E",
|
|
10
10
|
"spotEngine": "0xFcD94770B95fd9Cc67143132BB172EB17A0907fE",
|
|
11
11
|
"perpEngine": "0xF8599D58d1137fC56EcDd9C16ee139C8BDf96da1",
|
|
12
|
+
"offchainExchange": "0x8373C3Aa04153aBc0cfD28901c3c971a946994ab",
|
|
12
13
|
"airdrop": "0x0000000000000000000000000000000000000000",
|
|
13
14
|
"staking": "0x0000000000000000000000000000000000000000",
|
|
14
15
|
"foundationRewardsAirdrop": "0x0000000000000000000000000000000000000000"
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"endpoint": "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318",
|
|
10
10
|
"spotEngine": "0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82",
|
|
11
11
|
"perpEngine": "0x0B306BF915C4d645ff596e518fAf3F9669b97016",
|
|
12
|
+
"offchainExchange": "0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0",
|
|
12
13
|
"airdrop": "0x0000000000000000000000000000000000000000",
|
|
13
14
|
"staking": "0x0000000000000000000000000000000000000000",
|
|
14
15
|
"foundationRewardsAirdrop": "0x0000000000000000000000000000000000000000"
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"endpoint": "0x698D87105274292B5673367DEC81874Ce3633Ac2",
|
|
10
10
|
"spotEngine": "0x3352b2fF0fAc4ce38A6eA1C188cF4F924df54E5D",
|
|
11
11
|
"perpEngine": "0x4E859C47fea3666B5053B16C81AF64e77567702e",
|
|
12
|
+
"offchainExchange": "0x1e38180CFa9100b653c1Ea73B1B8175Aca1a45d0",
|
|
12
13
|
"airdrop": "0x0000000000000000000000000000000000000000",
|
|
13
14
|
"staking": "0x0000000000000000000000000000000000000000",
|
|
14
15
|
"foundationRewardsAirdrop": "0x0000000000000000000000000000000000000000"
|
nado_protocol/contracts/types.py
CHANGED
|
@@ -30,6 +30,7 @@ class NadoAbiName(StrEnum):
|
|
|
30
30
|
FQUERIER = "FQuerier"
|
|
31
31
|
ICLEARINGHOUSE = "IClearinghouse"
|
|
32
32
|
IENDPOINT = "IEndpoint"
|
|
33
|
+
IOFFCHAIN_EXCHANGE = "IOffchainExchange"
|
|
33
34
|
IPERP_ENGINE = "IPerpEngine"
|
|
34
35
|
ISPOT_ENGINE = "ISpotEngine"
|
|
35
36
|
MOCK_ERC20 = "MockERC20"
|
|
@@ -74,6 +75,7 @@ class NadoDeployment(NadoBaseModel):
|
|
|
74
75
|
airdrop_addr: str = Field(alias="airdrop")
|
|
75
76
|
staking_addr: str = Field(alias="staking")
|
|
76
77
|
foundation_rewards_airdrop_addr: str = Field(alias="foundationRewardsAirdrop")
|
|
78
|
+
offchain_exchange_addr: str = Field(alias="offchainExchange")
|
|
77
79
|
|
|
78
80
|
|
|
79
81
|
class DepositCollateralParams(NadoBaseModel):
|
|
@@ -119,6 +121,38 @@ class ClaimFoundationRewardsContractParams(NadoBaseModel):
|
|
|
119
121
|
claim_proofs: list[ClaimFoundationRewardsProofStruct]
|
|
120
122
|
|
|
121
123
|
|
|
124
|
+
class ClaimBuilderFeeParams(NadoBaseModel):
|
|
125
|
+
"""
|
|
126
|
+
Parameters for claiming builder fees via slow mode transaction.
|
|
127
|
+
|
|
128
|
+
Attributes:
|
|
129
|
+
subaccount_owner (str): The address of the subaccount owner.
|
|
130
|
+
subaccount_name (str): The name of the subaccount (default: "default").
|
|
131
|
+
builder_id (int): The builder ID to claim fees for.
|
|
132
|
+
"""
|
|
133
|
+
|
|
134
|
+
subaccount_owner: str
|
|
135
|
+
subaccount_name: str = "default"
|
|
136
|
+
builder_id: int
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
class BuilderInfo(NadoBaseModel):
|
|
140
|
+
"""
|
|
141
|
+
Builder information from the OffchainExchange contract.
|
|
142
|
+
|
|
143
|
+
Attributes:
|
|
144
|
+
owner (str): The address that can claim builder fees.
|
|
145
|
+
default_fee_tier (int): The default fee tier for the builder.
|
|
146
|
+
lowest_fee_rate (int): The lowest fee rate (x18).
|
|
147
|
+
highest_fee_rate (int): The highest fee rate (x18).
|
|
148
|
+
"""
|
|
149
|
+
|
|
150
|
+
owner: str
|
|
151
|
+
default_fee_tier: int
|
|
152
|
+
lowest_fee_rate: int
|
|
153
|
+
highest_fee_rate: int
|
|
154
|
+
|
|
155
|
+
|
|
122
156
|
class NadoExecuteType(StrEnum):
|
|
123
157
|
"""
|
|
124
158
|
Enumeration of possible actions to execute in Nado.
|
|
@@ -18,14 +18,14 @@ class IndexerEventType(StrEnum):
|
|
|
18
18
|
WITHDRAW_COLLATERAL = "withdraw_collateral"
|
|
19
19
|
SETTLE_PNL = "settle_pnl"
|
|
20
20
|
MATCH_ORDERS = "match_orders"
|
|
21
|
-
MATCH_ORDER_A_M_M = "match_order_a_m_m"
|
|
22
|
-
SWAP_AMM = "swap_a_m_m"
|
|
23
21
|
MINT_NLP = "mint_nlp"
|
|
24
22
|
BURN_NLP = "burn_nlp"
|
|
25
23
|
MANUAL_ASSERT = "manual_assert"
|
|
26
24
|
LINK_SIGNER = "link_signer"
|
|
27
25
|
TRANSFER_QUOTE = "transfer_quote"
|
|
28
26
|
CREATE_ISOLATED_SUBACCOUNT = "create_isolated_subaccount"
|
|
27
|
+
CLOSE_ISOLATED_SUBACCOUNT = "close_isolated_subaccount"
|
|
28
|
+
CLAIM_BUILDER_FEE = "claim_builder_fee"
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
class IndexerCandlesticksGranularity(IntEnum):
|
|
@@ -58,6 +58,7 @@ class IndexerOrderFill(IndexerBaseModel):
|
|
|
58
58
|
base_filled: str
|
|
59
59
|
quote_filled: str
|
|
60
60
|
fee: str
|
|
61
|
+
builder_fee: str
|
|
61
62
|
|
|
62
63
|
|
|
63
64
|
class IndexerHistoricalOrder(IndexerOrderFill):
|
|
@@ -67,6 +68,7 @@ class IndexerHistoricalOrder(IndexerOrderFill):
|
|
|
67
68
|
price_x18: str
|
|
68
69
|
expiration: str
|
|
69
70
|
nonce: str
|
|
71
|
+
appendix: str
|
|
70
72
|
isolated: bool
|
|
71
73
|
|
|
72
74
|
|
|
@@ -77,6 +79,7 @@ class IndexerSignedOrder(NadoBaseModel):
|
|
|
77
79
|
|
|
78
80
|
class IndexerMatch(IndexerOrderFill):
|
|
79
81
|
order: IndexerBaseOrder
|
|
82
|
+
sequencer_fee: str
|
|
80
83
|
cumulative_fee: str
|
|
81
84
|
cumulative_base_filled: str
|
|
82
85
|
cumulative_quote_filled: str
|
nado_protocol/utils/__init__.py
CHANGED
|
@@ -6,6 +6,7 @@ from nado_protocol.utils.math import *
|
|
|
6
6
|
from nado_protocol.utils.nonce import *
|
|
7
7
|
from nado_protocol.utils.exceptions import *
|
|
8
8
|
from nado_protocol.utils.order import *
|
|
9
|
+
from nado_protocol.utils.slow_mode import *
|
|
9
10
|
|
|
10
11
|
__all__ = [
|
|
11
12
|
"NadoBackendURL",
|
|
@@ -53,4 +54,11 @@ __all__ = [
|
|
|
53
54
|
"order_trigger_type",
|
|
54
55
|
"order_twap_data",
|
|
55
56
|
"order_execution_type",
|
|
57
|
+
# Builder utilities
|
|
58
|
+
"order_builder_id",
|
|
59
|
+
"order_builder_fee_rate",
|
|
60
|
+
"order_builder_info",
|
|
61
|
+
# Slow mode utilities
|
|
62
|
+
"SlowModeTxType",
|
|
63
|
+
"encode_claim_builder_fee_tx",
|
|
56
64
|
]
|
nado_protocol/utils/order.py
CHANGED
|
@@ -8,9 +8,9 @@ APPENDIX_VERSION = 1
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
class AppendixBitFields:
|
|
11
|
-
# | value | reserved | trigger | reduce only | order type| isolated | version |
|
|
12
|
-
# | 64 bits |
|
|
13
|
-
# | 127..64 | 63..14 | 13..12 | 11 | 10..9 | 8 | 7..0 |
|
|
11
|
+
# | value | builderId | builderFeeRate | reserved | trigger | reduce only | order type| isolated | version |
|
|
12
|
+
# | 64 bits | 16 bits | 10 bits | 24 bits | 2 bits | 1 bit | 2 bits | 1 bit | 8 bits |
|
|
13
|
+
# | 127..64 | 63..48 | 47..38 | 37..14 | 13..12 | 11 | 10..9 | 8 | 7..0 |
|
|
14
14
|
|
|
15
15
|
# Bit positions (from LSB to MSB)
|
|
16
16
|
VERSION_BITS = 8 # bits 7..0
|
|
@@ -18,7 +18,9 @@ class AppendixBitFields:
|
|
|
18
18
|
ORDER_TYPE_BITS = 2 # bits 10..9
|
|
19
19
|
REDUCE_ONLY_BITS = 1 # bit 11
|
|
20
20
|
TRIGGER_TYPE_BITS = 2 # bits 13..12
|
|
21
|
-
RESERVED_BITS =
|
|
21
|
+
RESERVED_BITS = 24 # bits 37..14
|
|
22
|
+
BUILDER_FEE_RATE_BITS = 10 # bits 47..38
|
|
23
|
+
BUILDER_ID_BITS = 16 # bits 63..48
|
|
22
24
|
VALUE_BITS = 64 # bits 127..64 (for isolated margin or TWAP data)
|
|
23
25
|
|
|
24
26
|
# Bit masks
|
|
@@ -28,6 +30,8 @@ class AppendixBitFields:
|
|
|
28
30
|
REDUCE_ONLY_MASK = (1 << REDUCE_ONLY_BITS) - 1
|
|
29
31
|
TRIGGER_TYPE_MASK = (1 << TRIGGER_TYPE_BITS) - 1
|
|
30
32
|
RESERVED_MASK = (1 << RESERVED_BITS) - 1
|
|
33
|
+
BUILDER_FEE_RATE_MASK = (1 << BUILDER_FEE_RATE_BITS) - 1
|
|
34
|
+
BUILDER_ID_MASK = (1 << BUILDER_ID_BITS) - 1
|
|
31
35
|
VALUE_MASK = (1 << VALUE_BITS) - 1
|
|
32
36
|
|
|
33
37
|
# Bit shift positions
|
|
@@ -37,6 +41,8 @@ class AppendixBitFields:
|
|
|
37
41
|
REDUCE_ONLY_SHIFT = 11
|
|
38
42
|
TRIGGER_TYPE_SHIFT = 12
|
|
39
43
|
RESERVED_SHIFT = 14
|
|
44
|
+
BUILDER_FEE_RATE_SHIFT = 38
|
|
45
|
+
BUILDER_ID_SHIFT = 48
|
|
40
46
|
VALUE_SHIFT = 64
|
|
41
47
|
|
|
42
48
|
|
|
@@ -111,6 +117,8 @@ def build_appendix(
|
|
|
111
117
|
isolated_margin: Optional[int] = None,
|
|
112
118
|
twap_times: Optional[int] = None,
|
|
113
119
|
twap_slippage_frac: Optional[float] = None,
|
|
120
|
+
builder_id: Optional[int] = None,
|
|
121
|
+
builder_fee_rate: Optional[int] = None,
|
|
114
122
|
_version: Optional[int] = APPENDIX_VERSION,
|
|
115
123
|
) -> int:
|
|
116
124
|
"""
|
|
@@ -124,6 +132,8 @@ def build_appendix(
|
|
|
124
132
|
isolated_margin (Optional[int]): Margin amount for isolated position if isolated is True.
|
|
125
133
|
twap_times (Optional[int]): Number of TWAP executions (required for TWAP trigger type).
|
|
126
134
|
twap_slippage_frac (Optional[float]): TWAP slippage fraction (required for TWAP trigger type).
|
|
135
|
+
builder_id (Optional[int]): Builder ID for fee sharing (16 bits, max 65535).
|
|
136
|
+
builder_fee_rate (Optional[int]): Builder fee rate as raw 10-bit integer (0-1023), each unit = 0.1 bps.
|
|
127
137
|
|
|
128
138
|
Returns:
|
|
129
139
|
int: The built appendix value with version set to APPENDIX_VERSION.
|
|
@@ -151,6 +161,12 @@ def build_appendix(
|
|
|
151
161
|
"twap_times and twap_slippage_frac are required for TWAP orders"
|
|
152
162
|
)
|
|
153
163
|
|
|
164
|
+
# Builder validation: both must be provided together or neither
|
|
165
|
+
if (builder_id is None) != (builder_fee_rate is None):
|
|
166
|
+
raise ValueError(
|
|
167
|
+
"builder_id and builder_fee_rate must both be provided or both be None"
|
|
168
|
+
)
|
|
169
|
+
|
|
154
170
|
appendix = 0
|
|
155
171
|
|
|
156
172
|
version = _version if _version is not None else APPENDIX_VERSION
|
|
@@ -179,6 +195,15 @@ def build_appendix(
|
|
|
179
195
|
trigger_value & AppendixBitFields.TRIGGER_TYPE_MASK
|
|
180
196
|
) << AppendixBitFields.TRIGGER_TYPE_SHIFT
|
|
181
197
|
|
|
198
|
+
# Builder fields (bits 47..38 for fee rate, bits 63..48 for id)
|
|
199
|
+
if builder_id is not None and builder_fee_rate is not None:
|
|
200
|
+
appendix |= (
|
|
201
|
+
builder_fee_rate & AppendixBitFields.BUILDER_FEE_RATE_MASK
|
|
202
|
+
) << AppendixBitFields.BUILDER_FEE_RATE_SHIFT
|
|
203
|
+
appendix |= (
|
|
204
|
+
builder_id & AppendixBitFields.BUILDER_ID_MASK
|
|
205
|
+
) << AppendixBitFields.BUILDER_ID_SHIFT
|
|
206
|
+
|
|
182
207
|
# Handle upper bits (127..64) based on order type
|
|
183
208
|
if isolated and isolated_margin is not None:
|
|
184
209
|
# Isolated margin (bits 127..64)
|
|
@@ -348,3 +373,57 @@ def order_execution_type(appendix: int) -> OrderType:
|
|
|
348
373
|
appendix >> AppendixBitFields.ORDER_TYPE_SHIFT
|
|
349
374
|
) & AppendixBitFields.ORDER_TYPE_MASK
|
|
350
375
|
return OrderType(order_type_bits)
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
def order_builder_id(appendix: int) -> Optional[int]:
|
|
379
|
+
"""
|
|
380
|
+
Extracts the builder ID from the appendix value.
|
|
381
|
+
|
|
382
|
+
Args:
|
|
383
|
+
appendix (int): The order appendix value.
|
|
384
|
+
|
|
385
|
+
Returns:
|
|
386
|
+
Optional[int]: The builder ID if set (non-zero), None otherwise.
|
|
387
|
+
"""
|
|
388
|
+
builder_id = (
|
|
389
|
+
appendix >> AppendixBitFields.BUILDER_ID_SHIFT
|
|
390
|
+
) & AppendixBitFields.BUILDER_ID_MASK
|
|
391
|
+
return builder_id if builder_id > 0 else None
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
def order_builder_fee_rate(appendix: int) -> Optional[int]:
|
|
395
|
+
"""
|
|
396
|
+
Extracts the builder fee rate from the appendix value.
|
|
397
|
+
|
|
398
|
+
Args:
|
|
399
|
+
appendix (int): The order appendix value.
|
|
400
|
+
|
|
401
|
+
Returns:
|
|
402
|
+
Optional[int]: The builder fee rate if builder is set, None otherwise.
|
|
403
|
+
This is a raw 10-bit integer (0-1023) where each unit = 0.1 bps.
|
|
404
|
+
"""
|
|
405
|
+
builder_id = order_builder_id(appendix)
|
|
406
|
+
if builder_id is None:
|
|
407
|
+
return None
|
|
408
|
+
return (
|
|
409
|
+
appendix >> AppendixBitFields.BUILDER_FEE_RATE_SHIFT
|
|
410
|
+
) & AppendixBitFields.BUILDER_FEE_RATE_MASK
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
def order_builder_info(appendix: int) -> Optional[tuple[int, int]]:
|
|
414
|
+
"""
|
|
415
|
+
Extracts builder info (id and fee rate) from the appendix value.
|
|
416
|
+
|
|
417
|
+
Args:
|
|
418
|
+
appendix (int): The order appendix value.
|
|
419
|
+
|
|
420
|
+
Returns:
|
|
421
|
+
Optional[tuple[int, int]]: Tuple of (builder_id, builder_fee_rate) if set, None otherwise.
|
|
422
|
+
"""
|
|
423
|
+
builder_id = order_builder_id(appendix)
|
|
424
|
+
if builder_id is None:
|
|
425
|
+
return None
|
|
426
|
+
fee_rate = (
|
|
427
|
+
appendix >> AppendixBitFields.BUILDER_FEE_RATE_SHIFT
|
|
428
|
+
) & AppendixBitFields.BUILDER_FEE_RATE_MASK
|
|
429
|
+
return (builder_id, fee_rate)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Utilities for encoding slow mode transactions for on-chain submission.
|
|
3
|
+
|
|
4
|
+
Slow mode transactions are submitted directly to the Endpoint contract
|
|
5
|
+
via `submitSlowModeTransaction(bytes)`.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from eth_abi import encode
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# Slow mode transaction type constants
|
|
12
|
+
class SlowModeTxType:
|
|
13
|
+
CLAIM_BUILDER_FEE = 31
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def encode_claim_builder_fee_tx(sender: bytes, builder_id: int) -> bytes:
|
|
17
|
+
"""
|
|
18
|
+
Encodes a ClaimBuilderFee slow mode transaction.
|
|
19
|
+
|
|
20
|
+
This transaction is submitted on-chain via `endpoint.submitSlowModeTransaction(bytes)`.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
sender: The subaccount bytes32 that will receive the claimed fees.
|
|
24
|
+
builder_id: The builder ID to claim fees for.
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
bytes: The encoded transaction ready for submission.
|
|
28
|
+
|
|
29
|
+
Example:
|
|
30
|
+
```python
|
|
31
|
+
from nado_protocol.utils.slow_mode import encode_claim_builder_fee_tx
|
|
32
|
+
from nado_protocol.utils.bytes32 import subaccount_to_bytes32
|
|
33
|
+
|
|
34
|
+
sender = subaccount_to_bytes32({"subaccount_owner": "0x...", "subaccount_name": "default"})
|
|
35
|
+
tx_bytes = encode_claim_builder_fee_tx(sender, builder_id=1)
|
|
36
|
+
|
|
37
|
+
# Submit via endpoint contract
|
|
38
|
+
endpoint.functions.submitSlowModeTransaction(tx_bytes).transact()
|
|
39
|
+
```
|
|
40
|
+
"""
|
|
41
|
+
if len(sender) != 32:
|
|
42
|
+
raise ValueError("sender must be 32 bytes")
|
|
43
|
+
|
|
44
|
+
# Encode the parameters: (bytes32 sender, uint32 builderId)
|
|
45
|
+
tx_bytes = encode(["bytes32", "uint32"], [sender, builder_id])
|
|
46
|
+
|
|
47
|
+
# Prepend the transaction type byte
|
|
48
|
+
return bytes([SlowModeTxType.CLAIM_BUILDER_FEE]) + tx_bytes
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
nado_protocol/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
nado_protocol/client/__init__.py,sha256=
|
|
2
|
+
nado_protocol/client/__init__.py,sha256=t_GNCLsmB9tE6YBM8rZxADRg2rvwlpLMg_bkLYgeA2w,8164
|
|
3
3
|
nado_protocol/client/apis/__init__.py,sha256=0wEscoemkmvyyTlUAaIM2vSO9LD_yCCVf3loHwasG_4,680
|
|
4
4
|
nado_protocol/client/apis/base.py,sha256=89g6va4wcqbV7XLO0UBkKmmM2C2oDcYSzRjzaUnFcGQ,1807
|
|
5
5
|
nado_protocol/client/apis/market/__init__.py,sha256=uILwdGeWOzQRT7x8bxvof6_u4GpsG9tL9I0VBuDPSoE,1102
|
|
@@ -18,27 +18,28 @@ nado_protocol/client/apis/subaccount/__init__.py,sha256=vT857P7_DkIWvV0D5izFg52i
|
|
|
18
18
|
nado_protocol/client/apis/subaccount/execute.py,sha256=sbiR9VhRl713Cfus_fAzXQiYR6VZWzPROaTowQDGaA4,2005
|
|
19
19
|
nado_protocol/client/apis/subaccount/query.py,sha256=468nG9sNq2Kw8nE4iH5Y6R5yuPienyNHs_PPOlmHTVo,4808
|
|
20
20
|
nado_protocol/client/context.py,sha256=-H4FSuV-CG7nAConYq4RYjzH9baGU57DQVGDOyfV2X4,3448
|
|
21
|
-
nado_protocol/contracts/__init__.py,sha256=
|
|
21
|
+
nado_protocol/contracts/__init__.py,sha256=q7utjGWH2Pl5YRew2DWlFoygzbp4k_KxQg3OX3o2spI,16041
|
|
22
22
|
nado_protocol/contracts/abis/Endpoint.json,sha256=8bhbVCW8twMCeqNYXTOREBTBGHEl9fKCenJAEXYiOAY,10931
|
|
23
23
|
nado_protocol/contracts/abis/FQuerier.json,sha256=tEyNwMyU9TPFWA9lJ8kIUHuVICqwIqDkFSnVvKQ3rNQ,42323
|
|
24
24
|
nado_protocol/contracts/abis/IAirdrop.json,sha256=DHFQBab7D3ehHVpqLNXM62SgjyID8C6EE4p2wH9t9vo,1496
|
|
25
25
|
nado_protocol/contracts/abis/IClearinghouse.json,sha256=GKyU4wDrCjCO8lkzAh3Rehs2sqzdJ5Zdwp2magRodVg,15549
|
|
26
26
|
nado_protocol/contracts/abis/IEndpoint.json,sha256=G5rHWDHpey2kGt5xp-aExzo7vyiXDyyk9e6CKVupT4w,4140
|
|
27
27
|
nado_protocol/contracts/abis/IFoundationRewardsAirdrop.json,sha256=CZXya7fyBA4YNq514RcbCjpf9pcytfy5lvtFNl3AVB0,1503
|
|
28
|
+
nado_protocol/contracts/abis/IOffchainExchange.json,sha256=OTr9wchAiWSj82Iq2SWFGbFpkvrmVYQKz-o62uRVR04,909
|
|
28
29
|
nado_protocol/contracts/abis/IPerpEngine.json,sha256=7BnmSrZkTA-2x6TYXOeGRSYb59b6p3xXqDYENvw8CMc,12066
|
|
29
30
|
nado_protocol/contracts/abis/IProductEngine.json,sha256=kue-r5zHk_4Xoalqfo5MZ8QbH-RcEnP3SFm2oiq_DWM,4749
|
|
30
31
|
nado_protocol/contracts/abis/ISpotEngine.json,sha256=PHUyEwRClfB8raaV3fc8i4q6c-aathos12wbiDNJRnI,12894
|
|
31
32
|
nado_protocol/contracts/abis/IStaking.json,sha256=XhC143Lnmcv1ZBhiABXwc67_HyvbWsCuiNmJ0hzdq0s,5557
|
|
32
33
|
nado_protocol/contracts/abis/MockERC20.json,sha256=YaaVbvWsPuHyt1v6LIP34-oF8Df9yVe3UqLW3wTroD8,5697
|
|
33
|
-
nado_protocol/contracts/deployments/deployment.mainnet.json,sha256=
|
|
34
|
-
nado_protocol/contracts/deployments/deployment.testing.json,sha256=
|
|
35
|
-
nado_protocol/contracts/deployments/deployment.testnet.json,sha256=
|
|
34
|
+
nado_protocol/contracts/deployments/deployment.mainnet.json,sha256=IF1Tl9NXc8iiJ30ZB0Q2mnFfYs7pA5LLOFSRsmUabC4,810
|
|
35
|
+
nado_protocol/contracts/deployments/deployment.testing.json,sha256=rkpFu53hmu9BRWHQ7w-EjZD4VBWfPexYchgQmRiXlr4,772
|
|
36
|
+
nado_protocol/contracts/deployments/deployment.testnet.json,sha256=uORcaXWedOmj8bDkpnOG5tZm6QCFLHakFz-7weTdNcM,836
|
|
36
37
|
nado_protocol/contracts/eip712/__init__.py,sha256=q8eJd5oY7AQ5iLsS1CfbZr6vBWLSPVZv2dfMnRzfqQo,416
|
|
37
38
|
nado_protocol/contracts/eip712/domain.py,sha256=dZ5aKq2Y45-vzZUMQLuUTbFhH9-R-YEg4G2sVqXQFbQ,1179
|
|
38
39
|
nado_protocol/contracts/eip712/sign.py,sha256=WeipHcWaEP_vnmXpRH7_Ksm9uKDH2E4IkYYRI0_p2cY,2410
|
|
39
40
|
nado_protocol/contracts/eip712/types.py,sha256=uTfYD9hjoTozsUL2WTc_-2OREijbfv9FDBYuD1UjVHo,5117
|
|
40
41
|
nado_protocol/contracts/loader.py,sha256=_0W3ImcARs1bTu1lLMpHMrRNuEVYjrRWctvnEbKWoVg,1500
|
|
41
|
-
nado_protocol/contracts/types.py,sha256=
|
|
42
|
+
nado_protocol/contracts/types.py,sha256=a30aE4MgOtbL-rDZd6pqGY8n6C0zdM19RCpIp38DSKQ,5303
|
|
42
43
|
nado_protocol/engine_client/__init__.py,sha256=RE_MxQaQVIp0K5EDhR1_uTjLJgEJBx2fLnhepc3cuAg,1137
|
|
43
44
|
nado_protocol/engine_client/execute.py,sha256=gKCdeV9Cb1YjChW8ka-2LaC5jD_i3xTdEzH2Y1g1WKY,15379
|
|
44
45
|
nado_protocol/engine_client/query.py,sha256=vaQ_lTA6xO7puikPW527e5xeVDtF8xlAeANO73yfPZ4,16923
|
|
@@ -50,7 +51,7 @@ nado_protocol/engine_client/types/stream.py,sha256=F_AKqU4pClzUcM6D9Dc79f6Rmraah
|
|
|
50
51
|
nado_protocol/indexer_client/__init__.py,sha256=ea2exePtguCxJsBlisOQPtnFk8hRmFugeQAuSAaPhoc,922
|
|
51
52
|
nado_protocol/indexer_client/query.py,sha256=f-2RvdzDRmBI7J_nosMLOPkHuR1gVpp828hppG42I9w,13775
|
|
52
53
|
nado_protocol/indexer_client/types/__init__.py,sha256=p1Q0JVhx273MuH6Q2baOfVknnLkmuL8kH4TlHDSYVTc,3161
|
|
53
|
-
nado_protocol/indexer_client/types/models.py,sha256=
|
|
54
|
+
nado_protocol/indexer_client/types/models.py,sha256=uRHirrF_UBuX80jLlbW2RPr0excVayAlmBdopyjvmGk,7627
|
|
54
55
|
nado_protocol/indexer_client/types/query.py,sha256=g3bymk_Xpl3vK_z51178qEiDUsGAa5Oqe6jmSNhiMOc,16328
|
|
55
56
|
nado_protocol/trigger_client/__init__.py,sha256=kD_WJWGOCDwX7GvGF5VGZibWR2uPYRcWpIWht31PYR4,545
|
|
56
57
|
nado_protocol/trigger_client/execute.py,sha256=RJntq-JtVqnufOlWWlZYvvy6MRqkQetXTsM_E1zGRsg,15154
|
|
@@ -59,7 +60,7 @@ nado_protocol/trigger_client/types/__init__.py,sha256=Rj953ymGSNnVdOpDrwRuXmC_jh
|
|
|
59
60
|
nado_protocol/trigger_client/types/execute.py,sha256=y1rxiFy3I7V3BHLKL8wQFDCwmf78AKuf8wB_1K8HlbU,4671
|
|
60
61
|
nado_protocol/trigger_client/types/models.py,sha256=ZVDF3MFWoR39JBaTmSOTl1WnRnw46hjX-WN_a-g6zKk,1638
|
|
61
62
|
nado_protocol/trigger_client/types/query.py,sha256=O6qhFLL2IREHc_mf-jFMyuVSzH1RuwjM-8noolLmEaQ,5288
|
|
62
|
-
nado_protocol/utils/__init__.py,sha256=
|
|
63
|
+
nado_protocol/utils/__init__.py,sha256=b01LUWyPMEmI2yC4YAgSNeSC-8SiE32VfsbIwIqwSLs,1677
|
|
63
64
|
nado_protocol/utils/backend.py,sha256=JRzNVbsuLxamqI2cr6q3FEpiyju5mtPAFxUFibyFxf0,3944
|
|
64
65
|
nado_protocol/utils/balance.py,sha256=Pf6tdcxZSn2Ou8M3XJnBIhsMB85-E7VkZDUIaMuEIbg,7435
|
|
65
66
|
nado_protocol/utils/bytes32.py,sha256=FHeHs9Sf-S7GdFTF6ikuz_sEkM-fpRW-g3kbZawlMd4,5299
|
|
@@ -72,11 +73,12 @@ nado_protocol/utils/margin_manager.py,sha256=kZ0QC1LYBx7NVtF9WuUQ6BI0425Oo9G1lVJ
|
|
|
72
73
|
nado_protocol/utils/math.py,sha256=TyuMb9ZpwfjLh5fMrNnr_QQWSl3bVZnjODglcxT_XTI,1771
|
|
73
74
|
nado_protocol/utils/model.py,sha256=feU7cp0mSgNp-Z0dmC6VSFA6Mkjv3rNfoXdqsoZ7uGU,2087
|
|
74
75
|
nado_protocol/utils/nonce.py,sha256=DHNn5mzXdJRope8QLcDCMFe7Bk4PXLoR9VaFopfse7I,886
|
|
75
|
-
nado_protocol/utils/order.py,sha256=
|
|
76
|
+
nado_protocol/utils/order.py,sha256=R-MG8b9DevoamKB_gQps30cRsvS1_Ho2SOkjO2BObE0,13815
|
|
77
|
+
nado_protocol/utils/slow_mode.py,sha256=jOfyWmvPCxkh6ALhqXFva2A-Tc32er_xWoUB8--Rrng,1553
|
|
76
78
|
nado_protocol/utils/subaccount.py,sha256=WJ7lgU2RekuzJAZH-hhCTbIBlRsl2oHozBm7OEMRV74,495
|
|
77
79
|
nado_protocol/utils/time.py,sha256=tEwmrkc5VdzKLlgkJIAq2ce-nhrduJZNtVPydrrnTHs,360
|
|
78
80
|
nado_protocol/utils/twap.py,sha256=hfBVK0CBa8m4uBArxTnNRoJr3o1rJucyopR_8_9gkOo,6197
|
|
79
|
-
nado_protocol-0.3.
|
|
80
|
-
nado_protocol-0.3.
|
|
81
|
-
nado_protocol-0.3.
|
|
82
|
-
nado_protocol-0.3.
|
|
81
|
+
nado_protocol-0.3.3.dist-info/METADATA,sha256=f-WJ902MAeouVFQ0JpogjPnQ4cMrgyrK8liWPC7xNX0,9558
|
|
82
|
+
nado_protocol-0.3.3.dist-info/WHEEL,sha256=kJCRJT_g0adfAJzTx2GUMmS80rTJIVHRCfG0DQgLq3o,88
|
|
83
|
+
nado_protocol-0.3.3.dist-info/entry_points.txt,sha256=Wdj1ww9VbRHpucpITSv0MyIgKy46SV87jQs6SczjHRA,374
|
|
84
|
+
nado_protocol-0.3.3.dist-info/RECORD,,
|