Skip to content
This repository was archived by the owner on Jan 19, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "bluefin_v2_client"
version = "2.1.0"
version = "2.1.1"
description = "Library to interact with Bluefin exchange protocol including its off-chain api-gateway and on-chain contracts"
readme = "README.md"
requires-python = ">=3.8"
Expand Down
51 changes: 23 additions & 28 deletions src/bluefin_v2_client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from .contracts import Contracts
from .order_signer import OrderSigner
from .onboarding_signer import OnboardingSigner
from .constants import TIME, SERVICE_URLS, CONTRACTS_BASE_NUM
from .constants import TIME, SERVICE_URLS
from .sockets_lib import Sockets
from .websocket_client import WebsocketClient
from .signer import Signer
Expand All @@ -15,10 +15,14 @@
from .interfaces import *
from .enumerations import *

_SUI_BASE_NUM = 1000000000
DEAULT_EXCHANGE_LEVERAGE = 3


class BluefinClient:
"""
A class to represent a client for interacting with bluefin offchain and onchain APIs.
"""

def __init__(self, are_terms_accepted, network, private_key=""):
self.are_terms_accepted = are_terms_accepted
self.network = network
Expand Down Expand Up @@ -153,9 +157,9 @@ def create_signed_order(self, req: OrderSignatureRequest) -> OrderSignatureRespo
OrderSignatureResponse: order raw info and generated signature
"""
sui_params = deepcopy(req)
sui_params["price"] = toDapiBase(req["price"])
sui_params["quantity"] = toDapiBase(req["quantity"])
sui_params["leverage"] = toDapiBase(req["leverage"])
sui_params["price"] = to1e18(req["price"])
sui_params["quantity"] = to1e18(req["quantity"])
sui_params["leverage"] = to1e18(req["leverage"])

order = self.create_order_to_sign(sui_params)
symbol = sui_params["symbol"].value
Expand Down Expand Up @@ -193,9 +197,9 @@ def create_signed_cancel_order(
OrderSignatureResponse: generated cancel signature
"""
sui_params = deepcopy(params)
sui_params["price"] = toDapiBase(params["price"])
sui_params["quantity"] = toDapiBase(params["quantity"])
sui_params["leverage"] = toDapiBase(params["leverage"])
sui_params["price"] = to1e18(params["price"])
sui_params["quantity"] = to1e18(params["quantity"])
sui_params["leverage"] = to1e18(params["leverage"])

order_to_sign = self.create_order_to_sign(sui_params)
hash_val = self.order_signer.get_order_hash(order_to_sign, withBufferHex=False)
Expand Down Expand Up @@ -313,7 +317,7 @@ async def post_signed_order(self, params: PlaceOrderRequest):
),
"postOnly": default_value(params, "postOnly", False),
"cancelOnRevert": default_value(params, "cancelOnRevert", False),
"clientId": "bluefin-python-client: {}".format(
"clientId": "bluefin-v2-client-python: {}".format(
default_value(params, "clientId", "bluefin-python-client")
),
},
Expand All @@ -336,7 +340,7 @@ async def deposit_margin_to_bank(self, amount: int, coin_id: str) -> bool:
callArgs = []
callArgs.append(self.contracts.get_bank_id())
callArgs.append(self.account.getUserAddress())
callArgs.append(str(toSuiBase(amount, base=CONTRACTS_BASE_NUM)))
callArgs.append(str(toUsdcBase(amount)))
callArgs.append(coin_id)
txBytes = rpc_unsafe_moveCall(
self.url,
Expand Down Expand Up @@ -371,7 +375,7 @@ async def withdraw_margin_from_bank(self, amount: Union[float, int]) -> bool:
callArgs = [
bank_id,
account_address,
str(toSuiBase(amount, base=CONTRACTS_BASE_NUM)),
str(toUsdcBase(amount)),
]
txBytes = rpc_unsafe_moveCall(
self.url,
Expand Down Expand Up @@ -438,14 +442,13 @@ async def adjust_leverage(self, symbol, leverage, parentAddress: str = ""):

account_address = self.account.address if parentAddress == "" else parentAddress
# implies user has an open position on-chain, perform on-chain leverage update
open_position = True
if user_position != {}:
callArgs = []
callArgs.append(self.contracts.get_perpetual_id(symbol))
callArgs.append(self.contracts.get_bank_id())
callArgs.append(self.contracts.get_sub_account_id())
callArgs.append(account_address)
callArgs.append(str(toDapiBase(leverage)))
Comment thread
yasir7ca marked this conversation as resolved.
callArgs.append(str(to1e18(leverage)))
callArgs.append(self.contracts.get_price_oracle_object_id(symbol))
txBytes = rpc_unsafe_moveCall(
self.url,
Expand All @@ -467,7 +470,7 @@ async def adjust_leverage(self, symbol, leverage, parentAddress: str = ""):
{
"symbol": symbol.value,
"address": account_address,
"leverage": toDapiBase(leverage),
"leverage": to1e18(leverage),
"marginType": MARGIN_TYPE.ISOLATED.value,
},
auth_required=True,
Expand Down Expand Up @@ -507,7 +510,7 @@ async def adjust_margin(

callArgs.append(self.contracts.get_sub_account_id())
callArgs.append(self.account.getUserAddress())
callArgs.append(str(toDapiBase(amount)))
callArgs.append(str(to1e18(amount)))
callArgs.append(self.contracts.get_price_oracle_object_id(symbol))
if operation == ADJUST_MARGIN.ADD:
txBytes = rpc_unsafe_moveCall(
Expand Down Expand Up @@ -578,7 +581,7 @@ async def get_native_chain_token_balance(self) -> float:
result = rpc_call_sui_function(
self.url, callArgs, method="suix_getBalance"
)["totalBalance"]
return self._from_sui_base(result)
return fromSuiBase(result)
except Exception as e:
raise (Exception(f"Failed to get balance, error: {e}"))

Expand Down Expand Up @@ -606,7 +609,7 @@ async def get_usdc_balance(self) -> float:
result = rpc_call_sui_function(
self.url, callArgs, method="suix_getBalance"
)["totalBalance"]
return self._from_sui_base(result)
return fromSuiBase(result)

except Exception as e:
raise (Exception("Failed to get balance, Exception: {}".format(e)))
Expand All @@ -625,7 +628,7 @@ async def get_margin_bank_balance(self) -> float:
self.url, call_args, method="suix_getDynamicFieldObject"
)

balance = fromDapiBase(
balance = from1e18(
result["data"]["content"]["fields"]["value"]["fields"]["balance"]
)
return balance
Expand Down Expand Up @@ -894,10 +897,9 @@ async def get_user_leverage(self, symbol: MARKET_SYMBOLS, parentAddress: str = "

for i in account_data_by_market:
if symbol.value == i["symbol"]:
return fromDapiBase(int(i["selectedLeverage"]))
# default leverage on system is 3
return from1e18(int(i["selectedLeverage"]))
Comment thread
yasir7ca marked this conversation as resolved.
# todo fetch from exchange info route
return 3
return DEAULT_EXCHANGE_LEVERAGE

async def get_cancel_on_disconnect_timer(
self, params: GetCancelOnDisconnectTimerRequest = None
Expand Down Expand Up @@ -952,10 +954,3 @@ async def close_connections(self):
# close aio http connection
await self.apis.close_session()
await self.dms_api.close_session()

def _from_sui_base(self, number: Union[str, int]) -> float:
number = float(number)
return number / float(_SUI_BASE_NUM)

def _to_sui_base(self, number: Union[int, float]) -> int:
return int(number * _SUI_BASE_NUM)
4 changes: 0 additions & 4 deletions src/bluefin_v2_client/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,3 @@
"ORDERS_HASH": "/orders/hash",
},
}

SUI_BASE_NUM = 1000000000
DAPI_BASE_NUM = 1000000000000000000
CONTRACTS_BASE_NUM = 1000000
37 changes: 25 additions & 12 deletions src/bluefin_v2_client/utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,46 @@

# from web3 import Web3
import time
from typing import Union
import bip_utils
import hashlib
from typing import Union
from .constants import SUI_BASE_NUM, DAPI_BASE_NUM, CONTRACTS_BASE_NUM


def toDapiBase(number: Union[int, float]) -> int:
return int(number * DAPI_BASE_NUM)
BASE_1E18 = 1000000000000000000
BASE_1E6 = 1000000 # 1e6 for USDC token
BASE_1E9 = 1000000000


def fromDapiBase(number: Union[int, float], dtype=int) -> int:
return dtype(number / DAPI_BASE_NUM)
def to1e18(number: Union[int, float]) -> int:
"""Takes in a number and multiples it by 1e18"""
return int(number * BASE_1E18)


def toSuiBase(number: Union[int, float], base=SUI_BASE_NUM) -> int:
return int(number * base)
def from1e18(number: Union[str, int]) -> float:
"""Takes in a number and divides it by 1e18"""
number = float(number)
return number / float(BASE_1E18)


def fromSuiBase(number: Union[str, int], base=SUI_BASE_NUM) -> float:
def fromSuiBase(number: Union[str, int]) -> float:
"""Takes in a number and divides it by 1e9"""
number = float(number)
return number / float(base)
return number / float(BASE_1E9)


def toUsdcBase(number: Union[int, float]) -> int:
"""Converts a number to usdc contract onchain representation i.e. multiply it by 1e6"""
return int(number * BASE_1E6)


def fromUsdcBase(number: Union[str, int]) -> float:
"""Converts a usdc quantity to number i.e. divide it by 1e6"""
number = float(number)
return number / float(BASE_1E6)


def numberToHex(num, pad=32):
# converting number to Hexadecimal format
hexNum = hex(num)

# padding it with zero to make the size 32 bytes
padHex = hexNum[2:].zfill(pad)
return padHex
Expand Down