Brine Connector NodeJS
Note:
This package has been deprecated. It is recommended to visit @tanx-libs/tanx-connector for the latest supported version.
Features
- Complete endpoints including REST and WebSockets
- Methods return parsed JSON.
- High level abstraction for ease of use.
- Easy authentication
- Automatically sets JWT token internally
- Calls refresh endpoint when token expires.
- Typescript Types✨
Brine Connector includes utility/connector functions which can be used to interact with the Brine API. It uses axios internally to handle all requests. It includes interceptors for setting JWT and handling re-login on token expiry.
Installation
First, go to Brine's Website and create an account with your wallet.
Install from npm
npm i @brine-fi/brine-connector
Getting Started
The default base url for mainnet is https://api.brine.fi and testnet is https://api-testnet.brine.fi. You can choose between mainnet and testnet by providing it through the constructor. The default is mainnet. All REST apis, WebSockets are handled by Client, WsClient classes respectively. All operations must be handled in a try-catch block.
Workflow
Check out the example files to see an example workflow.
To use library inside example files
npm run start
npm run start:ws
Rest Client
Import the REST Client
import { Client } from '@brine-fi/brine-connector'
Create a new instance.
Choose between mainnet or testnet
const client = new Client()
const client = new Client('testnet')
General Endpoints
Test connectivity
GET /sapi/v1/health/
client.testConnection()
24hr Price
GET /sapi/v1/market/tickers/
client.get24hPrice({ market: 'ethusdc' })
Kline/Candlestick Data
GET /sapi/v1/market/kline/
client.getCandlestick({
market: 'ethusdc',
period: 120,
})
Order Book
GET /sapi/v1/market/orderbook/
client.getOrderBook({
market: 'ethusdc',
})
Recent trades
GET /sapi/v1/market/trades/
client.getRecentTrades({
market: 'ethusdc',
})
Login
Both login
and completeLogin
sets JWT as Authorization Token. Optionally, setAccessToken
and setRefreshToken
can be used to set tokens directly.
getNonce: POST /sapi/v1/auth/nonce/
login: POST /sapi/v1/auth/login/
import { signMsg } from '@brine-fi/brine-connector'
const nonce = await client.getNonce(ethAddress)
const signedMsg = signMsg(nonce.payload, ethPrivateKey)
const loginRes = await client.login(ethAddress, signedMsg.signature)
const loginRes = await client.completeLogin(ethAddress, ethPrivateKey)
client.setAccessToken(access)
client.setRefreshToken(refresh)
Refresh Token
POST /sapi/v1/auth/token/refresh/
If refresh token is set (manually or by using login functions), the refresh endpoint is called automatically when access token expires. Optionally, you can call refreshTokens
manually by passing in refreshToken (passing it is optional, it'll work if has been set before).
const res = await client.refreshTokens(refreshToken)
Logout
Sets tokens to null
client.logOut()
Profile Information (Private 🔒)
GET /sapi/v1/user/profile/
client.getProfileInfo()
Balance details (Private 🔒)
GET /sapi/v1/user/balance/
client.getBalance()
Profit and Loss Details (Private 🔒)
GET /sapi/v1/user/pnl/
client.getProfitAndLoss()
Create order (Private 🔒)
Create Nonce Body
const nonceBody: CreateOrderNonceBody = {
market: 'ethusdc',
ord_type: 'market',
price: 29580.51,
side: 'buy',
volume: 0.0001,
}
If you are affiliated with the Brine organization, please ensure that you add the organization_key and api_key to the request body in both the nonce and create endpoints. This field is entirely optional. To obtain these keys, please reach out to Brine at support@brine.fi.
const nonceBody: CreateOrderNonceBody = {
market: 'ethusdc',
ord_type: 'market',
price: 29580.51,
side: 'buy',
volume: 0.0001,
organization_key: 'YOUR_ORGANIZATION_KEY',
api_key: 'YOUR_API_KEY',
}
Create Order
createOrderNonce: POST /sapi/v1/orders/nonce/
createNewOrder: POST /sapi/v1/orders/create/
const order = await client.createCompleteOrder(nonceBody, ethPrivateKey)
import { signMsgHash } from '@brine-fi/brine-connector'
const orderNonce = await client.createOrderNonce(nonceBody)
const signedBody = signMsgHash(orderNonce.payload, ethPrivateKey)
const order = await client.createNewOrder({
...signedBody,
organization_key: '',
api_key: '',
})
import {
createUserSignature,
getKeyPairFromSignature,
signOrderWithStarkKeys,
} from '@brine-fi/brine-connector'
const orderNonce = await client.createOrderNonce(nonceBody)
const userSignature = createUserSignature(ethPrivateKey, 'testnet')
const keyPair = getKeyPairFromSignature(userSignature.signature)
const signedBody = signOrderWithStarkKeys(keyPair, orderNonce.payload)
const order = await client.createNewOrder(signedBody)
Get Order (Private 🔒)
GET /sapi/v1/orders/{order_id}/
client.getOrder(orderId)
List orders (Private 🔒)
GET /sapi/v1/orders/
client.listOrders()
Cancel Order (Private 🔒)
POST /sapi/v1/orders/cancel/
client.cancelOrder(order_id)
List Trades (Private 🔒)
GET /sapi/v1/trades/
client.listTrades()
WebSocket Client
Import the WebSocket Client
import { WsClient } from '@brine-fi/brine-connector'
Create a new instance
const wsClient = new WsClient('public')
const wsClient = new WsClient('public', 'testnet')
const loginRes = await client.completeLogin(ethAddress, ethPrivateKey)
const wsClient = new WsClient('private', 'testnet', loginRes.token.access)
Connect
wsClient.connect()
Subscribe
const streams = ['btcusdc.trades', 'btcusdc.ob-inc', 'btcusdc.kline-5m']
wsClient.subscribe(streams)
wsClient.subscribe(['trade', 'order'])
Unsubscribe
const streams = ['btcusdc.trades', 'btcusdc.ob-inc', 'btcusdc.kline-5m']
wsClient.unsubscribe(streams)
wsClient.unsubscribe(['trade', 'order'])
Disconnect
wsClient.disconnect()
Usage
WsClient includes a member called ws which is initialized with the NodeJS WebSocket library (ws). You may use it to handle WebSocket operations.
wsClient.ws.on('message', (data) => {
console.log(data.toString())
})
Error Handling
Errors thrown are of types AuthenticationError | AxiosError
.
Example
import { isAuthenticationError } from '@brine-fi/brine-connector'
try {
} catch (e) {
if (isAuthenticationError(e)) {
console.log(e)
} else {
console.log(e as AxiosError<Response<string>>)
}
}
Create L2 Key Pair
You can create your own stark key pairs using the utility functions below
import { generateKeyPairFromEthPrivateKey } from '@brine-fi/brine-connector'
const keypair = generateKeyPairFromEthPrivateKey(ethPrivateKey, 'testnet')
const stark_public_key = keypair.getPublic().getX().toString('hex')
const stark_private_key = keypair.getPrivate().toString('hex')
Internal Transfer
Users will be able to seamlessly transfer assets from their CEXs or other chains with minimal fees.
To get started with the feature, follow these two steps:
-
Reach out to Brine (support@brine.fi) to get the organization key and API key.
-
Generate the L2 key pair with your private key using the following example:
import { generateKeyPairFromEthPrivateKey } from '@brine-fi/brine-connector'
const keypair = generateKeyPairFromEthPrivateKey(ethPrivateKey, 'testnet')
Available methods:
To process the internal transfer, call the initiateAndProcessInternalTransfers
method and pass the necessary arguments:
const internalTransferResponse =
await client.initiateAndProcessInternalTransfers(
keypair,
organizationKey,
apiKey,
'usdc',
amount,
destination_address,
client_reference_id,
)
Retrieve a list of transfers initiated by the authenticated user:
const internalTransferList = await client.listInternalTransfers({
limit: 10,
offset: 10,
})
Retrieve an internal transfer using its client reference id:
const internalTransferList = await client.getInternalTransferByClientId(
client_reference_id,
)
Check if a user exists by their destination address.
const checkUserRes = await client.checkInternalTransferUserExists(
brineOrganizationKey,
brineApiKey,
destination_address,
)
Deposit
Ethereum Deposit
There are two ways to make a deposit on the Ethereum network:
1. Using ETH Private Key and RPC URL:
In this method, you will use an ETH private key and an RPC URL to execute a deposit. You'll also need to create an RPC URL using services like Infura, Alchemy, etc. Here's the code snippet for this method:
const res = await client.depositFromEthereumNetwork(
process.env.RPC_PROVIDER as string,
privateKey,
'testnet',
'eth',
0.00001,
);
2. Using Custom Provider and Signer:
This method involves using a custom provider and signer, which can be created using the ethers.js library. The stark_public_key
mentioned in the code should be obtained using the steps described in the Create L2 Key Pair section. Here's the code snippet for this method:
import { Wallet, ethers } from 'ethers'
const provider = new ethers.providers.JsonRpcProvider(
process.env.RPC_PROVIDER,
)
const signer = new Wallet(privateKey, provider)
const depositRes = await client.depositFromEthereumNetworkWithStarkKey(
signer,
provider,
`0x${stark_public_key}`,
0.0000001,
'eth',
)
Polygon Deposit
There are two ways to make a deposit on the Polygon network:
1. Using ETH Private Key and RPC URL:
In this method, you will use an ETH private key and an RPC URL to execute a Polygon deposit. You'll also need to create an RPC URL using services like Infura, Alchemy, etc. Here's the code snippet for this method:
const depositRes = await client.depositFromPolygonNetwork(
process.env.RPC_PROVIDER as string,
privateKey,
'btc',
0.00001,
);
2. Using Custom Provider and Signer:
This method involves using a custom provider and signer, which can be created using the ethers.js library. Here's the code snippet for this method:
import { Wallet, ethers } from 'ethers'
const provider = new ethers.providers.JsonRpcProvider(
process.env.RPC_PROVIDER,
)
const signer = new Wallet(privateKey, provider)
const depositPolygonRes = await client.depositFromPolygonNetworkWithSigner(
signer,
provider,
'btc',
0.00001,
)
List Deposits
To get the deposit history, you can use the following code:
const depositsList = await client.listDeposits({
network: 'ETHEREUM',
page: 2,
limit: 1,
})
Withdrawal
Generally, we have two modes of withdrawal: Normal Withdrawal and Fast Withdrawal. For withdrawal methods that require a signer and provider, please refer to the deposit method mentioned above.
Normal Withdrawal
With Normal Withdrawal, your requested funds will be processed within a standard time frame (24 hours). This mode is suitable for users who are not in a rush to access their funds and are comfortable with the regular processing time.
const withdrawalRes = await client.initiateNormalWithdrawal(
keyPair,
0.0001,
'usdc',
)
const pendingBalance = await client.getPendingNormalWithdrawalAmountByCoin(
'eth',
ethAddress,
signer,
)
const completeNWRes = await client.completeNormalWithdrawal(
'eth',
ethAddress,
signer,
)
const withdrawalsList = await client.listNormalWithdrawals({
page: 2,
})
Fast Withdrawal
With Fast Withdrawal, your funds will be processed in an expedited timeframe, often within a few minutes. This mode is ideal for users who require immediate access to their funds and are comfortable with paying a fee.
const fastWithdrawalRes = await client.fastWithdrawal(
keyPair,
0.0001,
'usdc',
'ETHEREUM',
)
const fastwithdrawalsList = await client.listFastWithdrawals({
page: 2,
})
Polygon withdrawal
On the Polygon network, we only support fast withdrawals.
const fastWithdrawalRes = await client.fastWithdrawal(
keyPair,
0.0001,
'usdc',
'POLYGON',
)