diff --git a/.gitignore b/.gitignore index 994dae6..f77f5a6 100644 --- a/.gitignore +++ b/.gitignore @@ -66,4 +66,6 @@ target/ openapi-generator-cli.jar -.idea \ No newline at end of file +.idea + +examples/secrets.py \ No newline at end of file diff --git a/examples/transfer_update_leverage.py b/examples/transfer_update_leverage.py new file mode 100644 index 0000000..e5593b7 --- /dev/null +++ b/examples/transfer_update_leverage.py @@ -0,0 +1,47 @@ +import asyncio +import lighter + + +from examples.secrets import BASE_URL, API_KEY_PRIVATE_KEY, ETH_PRIVATE_KEY + +API_KEY_INDEX = 10 +TO_ACCOUNT_INDEX = 9 +ACCOUNT_INDEX = 10 # replace with your account_index + + +async def main(): + client = lighter.SignerClient( + url=BASE_URL, + private_key=API_KEY_PRIVATE_KEY, + account_index=ACCOUNT_INDEX, + api_key_index=API_KEY_INDEX, + ) + api_client = lighter.ApiClient(configuration=lighter.Configuration(host=BASE_URL)) + info_api = lighter.InfoApi(api_client) + order_api = lighter.OrderApi(api_client) + + auth_token, _ = client.create_auth_token_with_expiry() + fee_info = await info_api.transfer_fee_info(ACCOUNT_INDEX, authorization=auth_token, auth=auth_token, to_account_index=TO_ACCOUNT_INDEX) + print(fee_info) + + err = client.check_client() + if err is not None: + print(f"CheckClient error: {err}") + return + memo = "a"*32 # memo is a user message and it has to be exactly 32 bytes long + transfer_tx, response, err = await client.transfer( + ETH_PRIVATE_KEY, + usdc_amount=100, # decimals are added by sdk + to_account_index=TO_ACCOUNT_INDEX, + fee=fee_info.transfer_fee_usdc, + memo=memo, + ) + if err != None: + raise Exception(f"error transferring {err}") + print(transfer_tx, response) + + lev_tx, response, err = await client.update_leverage(4, client.CROSS_MARGIN_MODE, 3) + print(lev_tx, response, err) + +if __name__ == "__main__": + asyncio.run(main()) \ No newline at end of file diff --git a/lighter/models/trade.py b/lighter/models/trade.py index 8ae6eb1..9156a47 100644 --- a/lighter/models/trade.py +++ b/lighter/models/trade.py @@ -43,12 +43,12 @@ class Trade(BaseModel): taker_fee: Optional[StrictInt] taker_position_size_before: StrictStr taker_entry_quote_before: StrictStr - taker_initial_margin_fraction_before: StrictInt + taker_initial_margin_fraction_before: Optional[StrictInt] taker_position_sign_changed: Optional[StrictBool] maker_fee: Optional[StrictInt] maker_position_size_before: StrictStr maker_entry_quote_before: StrictStr - maker_initial_margin_fraction_before: StrictInt + maker_initial_margin_fraction_before: Optional[StrictInt] maker_position_sign_changed: Optional[StrictBool] additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["trade_id", "tx_hash", "type", "market_id", "size", "price", "usd_amount", "ask_id", "bid_id", "ask_account_id", "bid_account_id", "is_maker_ask", "block_height", "timestamp", "taker_fee", "taker_position_size_before", "taker_entry_quote_before", "taker_initial_margin_fraction_before", "taker_position_sign_changed", "maker_fee", "maker_position_size_before", "maker_entry_quote_before", "maker_initial_margin_fraction_before", "maker_position_sign_changed"] diff --git a/lighter/signer_client.py b/lighter/signer_client.py index 08dd529..12b81c5 100644 --- a/lighter/signer_client.py +++ b/lighter/signer_client.py @@ -128,6 +128,7 @@ class SignerClient: TX_TYPE_MODIFY_ORDER = 17 TX_TYPE_MINT_SHARES = 18 TX_TYPE_BURN_SHARES = 19 + TX_TYPE_UPDATE_LEVERAGE = 20 ORDER_TYPE_LIMIT = 0 ORDER_TYPE_MARKET = 1 @@ -151,6 +152,9 @@ class SignerClient: DEFAULT_10_MIN_AUTH_EXPIRY = -1 MINUTE = 60 + CROSS_MARGIN_MODE = 0 + ISOLATED_MARGIN_MODE = 1 + def __init__( self, url, @@ -422,20 +426,34 @@ def sign_modify_order(self, market_index, order_index, base_amount, price, trigg return tx_info, error - def sign_transfer(self, to_account_index, usdc_amount, nonce=-1): + def sign_transfer(self, eth_private_key, to_account_index, usdc_amount, fee, memo, nonce=-1): self.signer.SignTransfer.argtypes = [ ctypes.c_longlong, ctypes.c_longlong, ctypes.c_longlong, + ctypes.c_char_p, + ctypes.c_longlong, ] self.signer.SignTransfer.restype = StrOrErr + result = self.signer.SignTransfer(to_account_index, usdc_amount, fee, ctypes.c_char_p(memo.encode("utf-8")), nonce) - result = self.signer.SignTransfer(to_account_index, usdc_amount, nonce) - - tx_info = result.str.decode("utf-8") if result.str else None + tx_info_str = result.str.decode("utf-8") if result.str else None error = result.err.decode("utf-8") if result.err else None - return tx_info, error + if error: + return tx_info_str, error + + # fetch message to sign + tx_info = json.loads(tx_info_str) + msg_to_sign = tx_info["MessageToSign"] + del tx_info["MessageToSign"] + + # sign the message + acct = Account.from_key(eth_private_key) + message = encode_defunct(text=msg_to_sign) + signature = acct.sign_message(message) + tx_info["L1Sig"] = signature.signature.to_0x_hex() + return json.dumps(tx_info), None def sign_create_public_pool(self, operator_fee, initial_total_shares, min_operator_share_rate, nonce=-1): self.signer.SignCreatePublicPool.argtypes = [ @@ -502,19 +520,18 @@ def sign_burn_shares(self, public_pool_index, share_amount, nonce=-1): return tx_info, error - def sign_update_leverage(self, market_index, leverage, nonce=-1): + def sign_update_leverage(self, market_index, fraction, margin_mode, nonce=-1): self.signer.SignUpdateLeverage.argtypes = [ + ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_longlong, ] self.signer.SignUpdateLeverage.restype = StrOrErr - - result = self.signer.SignUpdateLeverage(market_index, leverage, nonce) + result = self.signer.SignUpdateLeverage(market_index, fraction, margin_mode, nonce) tx_info = result.str.decode("utf-8") if result.str else None error = result.err.decode("utf-8") if result.err else None - return tx_info, error def create_auth_token_with_expiry(self, deadline: int = DEFAULT_10_MIN_AUTH_EXPIRY): @@ -522,12 +539,10 @@ def create_auth_token_with_expiry(self, deadline: int = DEFAULT_10_MIN_AUTH_EXPI deadline = int(time.time() + 10 * SignerClient.MINUTE) self.signer.CreateAuthToken.argtypes = [ctypes.c_longlong] self.signer.CreateAuthToken.restype = StrOrErr - result = self.signer.CreateAuthToken(deadline) auth = result.str.decode("utf-8") if result.str else None error = result.err.decode("utf-8") if result.err else None - return auth, error async def change_api_key(self, eth_private_key: str, new_pubkey: str, nonce=-1): @@ -662,10 +677,10 @@ async def modify_order( return tx_info, api_response, None @process_api_key_and_nonce - async def transfer(self, to_account_index, usdc_amount, nonce=-1, api_key_index=-1): + async def transfer(self, eth_private_key: str, to_account_index, usdc_amount, fee, memo, nonce=-1, api_key_index=-1): usdc_amount = int(usdc_amount * self.USDC_TICKER_SCALE) - tx_info, error = self.sign_transfer(to_account_index, usdc_amount, nonce) + tx_info, error = self.sign_transfer(eth_private_key, to_account_index, usdc_amount, fee, memo, nonce) if error is not None: return None, None, error logging.debug(f"Transfer Tx Info: {tx_info}") @@ -725,6 +740,20 @@ async def burn_shares(self, public_pool_index, share_amount, nonce=-1, api_key_i api_response = await self.send_tx(tx_type=self.TX_TYPE_BURN_SHARES, tx_info=tx_info) logging.debug(f"Burn Shares Send Tx Response: {api_response}") return tx_info, api_response, None + + @process_api_key_and_nonce + async def update_leverage(self, market_index, margin_mode, leverage, nonce=-1, api_key_index=-1): + imf = int(10_000 / leverage) + tx_info, error = self.sign_update_leverage(market_index, imf, margin_mode, nonce) + + if error is not None: + return None, None, error + logging.debug(f"Update Leverage Tx Info: {tx_info}") + + api_response = await self.send_tx(tx_type=self.TX_TYPE_UPDATE_LEVERAGE, tx_info=tx_info) + logging.debug(f"Update Leverage Tx Response: {api_response}") + return tx_info, api_response, None + async def send_tx(self, tx_type: StrictInt, tx_info: str) -> RespSendTx: if tx_info[0] != "{": diff --git a/lighter/signers/signer-amd64.so b/lighter/signers/signer-amd64.so index 0ad5d7e..8cba2cd 100644 Binary files a/lighter/signers/signer-amd64.so and b/lighter/signers/signer-amd64.so differ diff --git a/lighter/signers/signer-arm64.dylib b/lighter/signers/signer-arm64.dylib index ef2f76e..d05dd5b 100644 Binary files a/lighter/signers/signer-arm64.dylib and b/lighter/signers/signer-arm64.dylib differ