diff --git a/examples/add_eth_margin.py b/examples/add_eth_margin.py new file mode 100644 index 0000000..18043a2 --- /dev/null +++ b/examples/add_eth_margin.py @@ -0,0 +1,62 @@ +import asyncio +import lighter +from utils import default_example_setup + + +async def fetch(api_client, idx): + return (await lighter.AccountApi(api_client).account(by="index", value=str(idx))).accounts[0] + +def eth_spot(a): + for x in a.assets: + if x.symbol == "ETH": + return float(x.balance) + return 0.0 + +def show(label, a): + print(f"\n[{label}] mode={a.account_trading_mode} tav={a.total_asset_value}") + for x in a.assets: + extra = getattr(x, "additional_properties", {}) or {} + mb = getattr(x, "margin_balance", None) or extra.get("margin_balance", "-") + mm = getattr(x, "margin_mode", None) or extra.get("margin_mode", "-") + print(f" {x.symbol:<6} spot={x.balance} margin={mb} mode={mm}") + + +async def wait_for_change(api_client, idx, prev, timeout=60): + for i in range(timeout * 2): + await asyncio.sleep(0.5) + a = await fetch(api_client, idx) + if abs(eth_spot(a) - prev) > 1e-9: + print(f"state updated after {(i+1)*0.5:.1f}s") + return a + print(f"timeout {timeout}s — state didn't change") + return await fetch(api_client, idx) + +async def main(): + client, api_client, _ = default_example_setup() + before = await fetch(api_client, client.account_index) + show("BEFORE", before) + + await client.update_account_config(account_trading_mode=1) + await client.update_account_asset_config( + asset_index=client.ASSET_ID_ETH, + asset_margin_mode=client.ASSET_MARGIN_MODE_ENABLED, + ) + await client.transfer_same_master_account( + to_account_index=client.account_index, + asset_id=client.ASSET_ID_ETH, + amount=1.0, + route_from=client.ROUTE_SPOT, + route_to=client.ROUTE_PERP, + fee=0, + memo="0x" + "00" * 32, + ) + + after = await wait_for_change(api_client, client.account_index, eth_spot(before)) + show("AFTER", after) + + await client.close() + await api_client.close() + + +if __name__ == "__main__": + asyncio.run(main()) \ No newline at end of file diff --git a/examples/disable_eth_as_margin.py b/examples/disable_eth_as_margin.py new file mode 100644 index 0000000..009c924 --- /dev/null +++ b/examples/disable_eth_as_margin.py @@ -0,0 +1,21 @@ +import asyncio +from utils import default_example_setup + + +async def main(): + client, api_client, _ = default_example_setup() + + tx, resp, err = await client.update_account_asset_config( + asset_index=client.ASSET_ID_ETH, + asset_margin_mode=client.ASSET_MARGIN_MODE_DISABLED, + ) + print(f"Enable ETH as margin: {tx=} {resp=} {err=}") + if err is not None: + raise Exception(err) + + await client.close() + await api_client.close() + + +if __name__ == "__main__": + asyncio.run(main()) \ No newline at end of file diff --git a/examples/enable_eth_as_margin.py b/examples/enable_eth_as_margin.py new file mode 100644 index 0000000..e5778e8 --- /dev/null +++ b/examples/enable_eth_as_margin.py @@ -0,0 +1,21 @@ +import asyncio +from utils import default_example_setup + + +async def main(): + client, api_client, _ = default_example_setup() + + tx, resp, err = await client.update_account_asset_config( + asset_index=client.ASSET_ID_ETH, + asset_margin_mode=client.ASSET_MARGIN_MODE_ENABLED, + ) + print(f"Enable ETH as margin: {tx=} {resp=} {err=}") + if err is not None: + raise Exception(err) + + await client.close() + await api_client.close() + + +if __name__ == "__main__": + asyncio.run(main()) \ No newline at end of file diff --git a/lighter/signer_client.py b/lighter/signer_client.py index 7d96b38..b598ccc 100644 --- a/lighter/signer_client.py +++ b/lighter/signer_client.py @@ -175,6 +175,9 @@ def __populate_shared_library_functions(signer): signer.SignUpdateAccountConfig.argtypes = [ctypes.c_uint8, ctypes.c_uint8, ctypes.c_longlong, ctypes.c_int, ctypes.c_longlong] signer.SignUpdateAccountConfig.restype = SignedTxResponse + signer.SignUpdateAccountAssetConfig.argtypes = [ctypes.c_int16, ctypes.c_uint8, ctypes.c_uint8, ctypes.c_longlong, ctypes.c_int, ctypes.c_longlong] + signer.SignUpdateAccountAssetConfig.restype = SignedTxResponse + signer.Free.argtypes = [ctypes.c_void_p] signer.Free.restype = None @@ -279,6 +282,9 @@ class SignerClient: CROSS_MARGIN_MODE = 0 ISOLATED_MARGIN_MODE = 1 + ASSET_MARGIN_MODE_DISABLED = 0 + ASSET_MARGIN_MODE_ENABLED = 1 + ISOLATED_MARGIN_REMOVE_COLLATERAL = 0 ISOLATED_MARGIN_ADD_COLLATERAL = 1 @@ -628,6 +634,9 @@ def sign_update_account_config(self, account_trading_mode: int, skip_nonce: int return self.__decode_tx_info(self.signer.SignUpdateAccountConfig(account_trading_mode, skip_nonce, nonce, api_key_index, self.account_index)) + def sign_update_account_asset_config(self, asset_index: int, asset_margin_mode: int, skip_nonce: int = SKIP_NONCE_OFF, nonce: int = DEFAULT_NONCE, api_key_index: int = DEFAULT_API_KEY_INDEX) -> Union[Tuple[str, str, str, None], Tuple[None, None, None, str]]: + return self.__decode_tx_info(self.signer.SignUpdateAccountAssetConfig(asset_index, asset_margin_mode, skip_nonce, nonce, api_key_index, self.account_index)) + @process_api_key_and_nonce async def create_order( self, @@ -1360,6 +1369,17 @@ async def update_account_config(self, account_trading_mode: int, skip_nonce: int api_response = await self.send_tx(tx_type=tx_type, tx_info=tx_info) return tx_info, api_response, None + @process_api_key_and_nonce + async def update_account_asset_config(self, asset_index: int, asset_margin_mode: int, skip_nonce: int = SKIP_NONCE_OFF, nonce: int = DEFAULT_NONCE, api_key_index: int = DEFAULT_API_KEY_INDEX): + tx_type, tx_info, tx_hash, error = self.sign_update_account_asset_config( + asset_index, asset_margin_mode, skip_nonce, nonce, api_key_index + ) + if error is not None: + return None, None, error + api_response = await self.send_tx(tx_type=tx_type, tx_info=tx_info) + return tx_info, api_response, None + + async def send_tx(self, tx_type: StrictInt, tx_info: str) -> RespSendTx: if tx_info[0] != "{": raise Exception(tx_info) diff --git a/lighter/signers/lighter-signer-darwin-arm64.dylib b/lighter/signers/lighter-signer-darwin-arm64.dylib index 0a4ae94..20b2830 100644 Binary files a/lighter/signers/lighter-signer-darwin-arm64.dylib and b/lighter/signers/lighter-signer-darwin-arm64.dylib differ diff --git a/lighter/signers/lighter-signer-darwin-arm64.h b/lighter/signers/lighter-signer-darwin-arm64.h index 9eebb30..ce31224 100644 --- a/lighter/signers/lighter-signer-darwin-arm64.h +++ b/lighter/signers/lighter-signer-darwin-arm64.h @@ -142,6 +142,7 @@ extern SignedTxResponse SignStakeAssets(long long cStakingPoolIndex, long long c extern SignedTxResponse SignUnstakeAssets(long long cStakingPoolIndex, long long cShareAmount, uint8_t cSkipNonce, long long cNonce, int cApiKeyIndex, long long cAccountIndex); extern SignedTxResponse SignApproveIntegrator(long long cIntegratorIndex, uint32_t cMaxPerpsTakerFee, uint32_t cMaxPerpsMakerFee, uint32_t cMaxSpotTakerFee, uint32_t cMaxSpotMakerFee, long long cApprovalExpiry, uint8_t cSkipNonce, long long cNonce, int cApiKeyIndex, long long cAccountIndex); extern SignedTxResponse SignUpdateAccountConfig(uint8_t cAccountTradingMode, uint8_t cSkipNonce, long long cNonce, int cApiKeyIndex, long long cAccountIndex); +extern SignedTxResponse SignUpdateAccountAssetConfig(int16_t cAssetIndex, uint8_t cAssetMarginMode, uint8_t cSkipNonce, long long cNonce, int cApiKeyIndex, long long cAccountIndex); extern void Free(void* ptr); #ifdef __cplusplus diff --git a/lighter/signers/lighter-signer-linux-amd64.h b/lighter/signers/lighter-signer-linux-amd64.h index 7542ea4..4888ef1 100644 --- a/lighter/signers/lighter-signer-linux-amd64.h +++ b/lighter/signers/lighter-signer-linux-amd64.h @@ -134,6 +134,7 @@ extern SignedTxResponse SignStakeAssets(long long int cStakingPoolIndex, long lo extern SignedTxResponse SignUnstakeAssets(long long int cStakingPoolIndex, long long int cShareAmount, uint8_t cSkipNonce, long long int cNonce, int cApiKeyIndex, long long int cAccountIndex); extern SignedTxResponse SignApproveIntegrator(long long int cIntegratorIndex, uint32_t cMaxPerpsTakerFee, uint32_t cMaxPerpsMakerFee, uint32_t cMaxSpotTakerFee, uint32_t cMaxSpotMakerFee, long long int cApprovalExpiry, uint8_t cSkipNonce, long long int cNonce, int cApiKeyIndex, long long int cAccountIndex); extern SignedTxResponse SignUpdateAccountConfig(uint8_t cAccountTradingMode, uint8_t cSkipNonce, long long int cNonce, int cApiKeyIndex, long long int cAccountIndex); +extern SignedTxResponse SignUpdateAccountAssetConfig(int16_t cAssetIndex, uint8_t cAssetMarginMode, uint8_t cSkipNonce, long long int cNonce, int cApiKeyIndex, long long int cAccountIndex); extern void Free(void* ptr); #ifdef __cplusplus diff --git a/lighter/signers/lighter-signer-linux-amd64.so b/lighter/signers/lighter-signer-linux-amd64.so index 59db5f0..3ddaff4 100644 Binary files a/lighter/signers/lighter-signer-linux-amd64.so and b/lighter/signers/lighter-signer-linux-amd64.so differ diff --git a/lighter/signers/lighter-signer-linux-arm64.h b/lighter/signers/lighter-signer-linux-arm64.h index 7542ea4..4888ef1 100644 --- a/lighter/signers/lighter-signer-linux-arm64.h +++ b/lighter/signers/lighter-signer-linux-arm64.h @@ -134,6 +134,7 @@ extern SignedTxResponse SignStakeAssets(long long int cStakingPoolIndex, long lo extern SignedTxResponse SignUnstakeAssets(long long int cStakingPoolIndex, long long int cShareAmount, uint8_t cSkipNonce, long long int cNonce, int cApiKeyIndex, long long int cAccountIndex); extern SignedTxResponse SignApproveIntegrator(long long int cIntegratorIndex, uint32_t cMaxPerpsTakerFee, uint32_t cMaxPerpsMakerFee, uint32_t cMaxSpotTakerFee, uint32_t cMaxSpotMakerFee, long long int cApprovalExpiry, uint8_t cSkipNonce, long long int cNonce, int cApiKeyIndex, long long int cAccountIndex); extern SignedTxResponse SignUpdateAccountConfig(uint8_t cAccountTradingMode, uint8_t cSkipNonce, long long int cNonce, int cApiKeyIndex, long long int cAccountIndex); +extern SignedTxResponse SignUpdateAccountAssetConfig(int16_t cAssetIndex, uint8_t cAssetMarginMode, uint8_t cSkipNonce, long long int cNonce, int cApiKeyIndex, long long int cAccountIndex); extern void Free(void* ptr); #ifdef __cplusplus diff --git a/lighter/signers/lighter-signer-linux-arm64.so b/lighter/signers/lighter-signer-linux-arm64.so index 99bc462..88e9694 100644 Binary files a/lighter/signers/lighter-signer-linux-arm64.so and b/lighter/signers/lighter-signer-linux-arm64.so differ diff --git a/lighter/signers/lighter-signer-windows-amd64.dll b/lighter/signers/lighter-signer-windows-amd64.dll index e2bd743..a2a54e3 100644 Binary files a/lighter/signers/lighter-signer-windows-amd64.dll and b/lighter/signers/lighter-signer-windows-amd64.dll differ diff --git a/lighter/signers/lighter-signer-windows-amd64.h b/lighter/signers/lighter-signer-windows-amd64.h index ce0b55c..1480ac9 100644 --- a/lighter/signers/lighter-signer-windows-amd64.h +++ b/lighter/signers/lighter-signer-windows-amd64.h @@ -134,6 +134,7 @@ extern __declspec(dllexport) SignedTxResponse SignStakeAssets(long long int cSta extern __declspec(dllexport) SignedTxResponse SignUnstakeAssets(long long int cStakingPoolIndex, long long int cShareAmount, uint8_t cSkipNonce, long long int cNonce, int cApiKeyIndex, long long int cAccountIndex); extern __declspec(dllexport) SignedTxResponse SignApproveIntegrator(long long int cIntegratorIndex, uint32_t cMaxPerpsTakerFee, uint32_t cMaxPerpsMakerFee, uint32_t cMaxSpotTakerFee, uint32_t cMaxSpotMakerFee, long long int cApprovalExpiry, uint8_t cSkipNonce, long long int cNonce, int cApiKeyIndex, long long int cAccountIndex); extern __declspec(dllexport) SignedTxResponse SignUpdateAccountConfig(uint8_t cAccountTradingMode, uint8_t cSkipNonce, long long int cNonce, int cApiKeyIndex, long long int cAccountIndex); +extern __declspec(dllexport) SignedTxResponse SignUpdateAccountAssetConfig(int16_t cAssetIndex, uint8_t cAssetMarginMode, uint8_t cSkipNonce, long long int cNonce, int cApiKeyIndex, long long int cAccountIndex); extern __declspec(dllexport) void Free(void* ptr); #ifdef __cplusplus