@firefly-exchange/library-sui
Version:
Sui library housing helper methods, classes to interact with Bluefin protocol(s) deployed on Sui
538 lines (537 loc) • 28.1 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RequestsBuilder = void 0;
const constants_1 = require("../constants");
const blake2b_1 = require("@noble/hashes/blake2b");
const library_1 = require("../library");
const utils_1 = require("./utils");
const bcs_1 = require("./utils/bcs");
const enums_1 = require("./enums");
class RequestsBuilder {
/**
* Class constructor
* @param _deployment the deployment config
* @param _signer the wallet/signer
* @param _walletAddress (optional) the wallet/signer address
*/
constructor(_deployment, _signer, _walletAddress) {
this.parser = new utils_1.DeploymentParser(_deployment);
this.signer = _signer;
this.walletAddress = _walletAddress || _signer?.toSuiAddress();
}
/**
* Create a withdrawal request for user to submit to bluefin gateway
* @param assetSymbol name of the asset to be withdrawn
* @param amountE9 amount to be withdrawn. Should be in 9 decimal places
* @param options Optional params:
* - salt: A random number to make the withdrawal payload unique for the user
* - account: The address of the account performing the withdraw
* - assetBankID: The address of the asset bank. By default fetches the asset bank of the provided asset symbol
* - eds: The id of the External Data store
* - signedAt: The timestamp in seconds at which the payload is signed
* @returns IRequestPayload
*/
async withdrawal(assetSymbol, amountE9, options) {
const rawData = {
type: enums_1.PAYLOAD_REQUEST_TYPE.WITHDRAWAL,
eds: options?.eds || this.parser.getExternalDataStore(),
assetSymbol,
account: options?.account || this.walletAddress,
amount: (0, library_1.bigNumber)(amountE9).toFixed(0),
salt: String(options?.salt || (0, utils_1.generateSalt)()),
signedAt: String(options?.signedAt || Date.now())
};
const serializedData = bcs_1.BCSUtils.getSerializedDataHex(rawData, bcs_1.Withdrawal);
// sign the payload
const signature = await utils_1.Signature.signRequest(options?.signer || this.signer, new TextEncoder().encode(JSON.stringify(rawData, null, 2)));
return { rawData, serializedData, signature };
}
/**
* Creates an authorized user request for user to submit to bluefin gateway
* @param user The address of the account to be authorized or unauthorized
* @param status a boolean indicating if the users are to be authorized or not
* @param options Optional params:
* - signer: The signer that will be signing the payload
* - account: The account for which to authorize users - defaults to `this.walletAddress`
* - ids: The internal data store id
* - salt: A random number to make the payload unique
* - signedAt: The timestamp in seconds at which the payload is signed
* @returns IRequestPayload
*/
async authorizeUser(user, status, options) {
const rawData = {
type: enums_1.PAYLOAD_REQUEST_TYPE.AUTHORIZE_ACCOUNT,
ids: options?.ids || this.parser.getInternalDataStore(),
account: options?.account || this.walletAddress,
user,
status,
salt: String(options?.salt || (0, utils_1.generateSalt)()),
signedAt: String(options?.signedAt || Date.now())
};
// serialize the payload
const serializedData = bcs_1.BCSUtils.getSerializedDataHex(rawData, bcs_1.AuthorizeUser);
// sign the payload
const signature = await utils_1.Signature.signRequest(options?.signer || this.signer, new TextEncoder().encode(JSON.stringify(rawData, null, 2)));
return { rawData, serializedData, signature };
}
/**
* Creates a signed order
* @param orderParams Params for order creation
* @param options Optional params
* - signer: the signer of the order
* - ids: The id of internal data store
* @returns IRequestPayload
*/
async createSignedOrder(orderParams, options) {
const signer = options?.signer || this.signer;
const ids = orderParams?.ids || this.parser.getInternalDataStore();
const account = orderParams.account || signer.toSuiAddress();
// build order
const rawData = {
type: enums_1.PAYLOAD_REQUEST_TYPE.ORDER,
ids,
account,
market: orderParams.market || "ETH-PERP",
price: (0, library_1.toBigNumberStr)(orderParams.price != undefined ? orderParams.price : 3500, constants_1.SUI_NATIVE_BASE),
quantity: (0, library_1.toBigNumberStr)(orderParams.quantity != undefined ? orderParams.quantity : 0.1, constants_1.SUI_NATIVE_BASE),
leverage: (0, library_1.toBigNumberStr)(orderParams.leverage != undefined ? orderParams.leverage : 0, constants_1.SUI_NATIVE_BASE),
side: orderParams.side || "LONG",
positionType: orderParams.positionType || enums_1.POSITION_TYPES.CROSS,
expiration: String(orderParams.expiration || 2037603360000),
salt: String(orderParams.salt || (0, utils_1.generateSalt)()),
signedAt: String(orderParams.signedAt || Date.now())
};
// serialize the payload
const serializedData = bcs_1.BCSUtils.getSerializedDataHex(rawData, bcs_1.Order);
// this is the order hash
const hash = Buffer.from((0, blake2b_1.blake2b)((0, library_1.hexStrToUint8)(serializedData), { dkLen: 32 })).toString("hex");
// sign the payload
const signature = await utils_1.Signature.signRequest(options?.signer || this.signer, new TextEncoder().encode(JSON.stringify(rawData, null, 2)));
return { rawData: { ...rawData, hash, signature }, serializedData, signature };
}
/**
* Create a liquidation request for user to submit to bluefin gateway
* @param liquidatee: The address of the account to be liquidated
* @param market: The symbol of the market/perpetual for which to liquidate user's position
* @param positionType: The type of position being liquidated
* @param assumeAs: The position to be assumed as isolated or cross
* @param quantityE9: The amount to be liquidated
* @param options Optional params:
* - signer: The signer to be used to sign the payload. Defaults to signer of the class (this.signer)
* - liquidator: The address of the liquidator. Defaults to the signer address
* - allOrNothing: True if the complete specified amount must be liquidated, false otherwise. Defaults to False
* - salt: A random number to make the payload unique
* - expiry: The timestamp till which the signed liquidation is valid
* - leverageE9: If assuming as an isolated position, specify the leverage. Defaults to 1 for isolated position, and passed as 0 for cross.
* - ids: The internal data store id/address
* - signedAt: The timestamp in seconds at which the payload is signed
* @returns IRequestPayload
*/
async createSignedLiquidation(liquidatee, market, positionType, assumeAs, quantityE9, options) {
const signer = options?.signer || this.signer;
const liquidator = options?.liquidator || signer.toSuiAddress();
const allOrNothing = options?.allOrNothing == true;
const leverageE9 = assumeAs == enums_1.ASSUME_AS.CROSS
? 0
: options?.leverageE9 || constants_1.BIGNUMBER_BASE_ON_CHAIN;
const expiry = options?.expiry || 2037603360000;
const salt = options?.salt || (0, utils_1.generateSalt)();
const ids = options?.ids || this.parser.getInternalDataStore();
// build liquidate request payload
const rawData = {
type: enums_1.PAYLOAD_REQUEST_TYPE.LIQUIDATE,
ids,
liquidatee,
liquidator,
market,
quantity: (0, library_1.bigNumber)(quantityE9).toFixed(0),
isolated: positionType == enums_1.POSITION_TYPES.ISOLATED,
assumeAsCross: assumeAs == enums_1.ASSUME_AS.CROSS,
allOrNothing,
leverage: (0, library_1.bigNumber)(leverageE9).toFixed(0),
expiry: String(expiry),
salt: String(salt),
signedAt: String(options?.signedAt || Date.now())
};
// serialize the payload
const serializedData = bcs_1.BCSUtils.getSerializedDataHex(rawData, bcs_1.Liquidate);
// sign the payload
const signature = await utils_1.Signature.signRequest(signer, (0, library_1.hexStrToUint8)(serializedData));
return { rawData, serializedData, signature };
}
/**
* Create an ADL request for user to submit to bluefin gateway
* @param maker: The address of the account to be deleveraged (bankrupt)
* @param taker: The address of the account to be deleveraged against +Pnl
* @param market: The symbol of the market/perpetual for which to liquidate user's position
* @param makerPositionType: The type of maker position being deleveraged
* @param takerPositionType: The type of taker position being deleveraged
* @param quantityE9: The amount to be deleveraged
* @param options Optional params:
* - signer: The signer to be used to sign the payload. Defaults to signer of the class (this.signer)
* - salt: A random number to make the payload unique
* - expiry: The timestamp till which the signed adl is valid
* - ids: The internal data store id/address
* - signedAt: The timestamp in seconds at which the payload is signed
* @returns IRequestPayload
*/
async createSignedADL(maker, taker, makerPositionType, takerPositionType, market, quantityE9, options) {
const signer = options?.signer || this.signer;
const expiry = options?.expiry || 2037603360000;
const salt = options?.salt || (0, utils_1.generateSalt)();
const ids = options?.ids || this.parser.getInternalDataStore();
// build liquidate request payload
const rawData = {
type: enums_1.PAYLOAD_REQUEST_TYPE.DELEVERAGE,
ids,
maker,
taker,
makerIsolated: makerPositionType == enums_1.POSITION_TYPES.ISOLATED,
takerIsolated: takerPositionType == enums_1.POSITION_TYPES.ISOLATED,
market,
quantity: (0, library_1.bigNumber)(quantityE9).toFixed(0),
expiry: String(expiry),
salt: String(salt),
signedAt: String(options?.signedAt || Date.now())
};
// serialize the payload
const serializedData = bcs_1.BCSUtils.getSerializedDataHex(rawData, bcs_1.Deleverage);
// sign the payload
const signature = await utils_1.Signature.signRequest(signer, (0, library_1.hexStrToUint8)(serializedData));
return { rawData, serializedData, signature };
}
/**
* Create a adjust margin request for user to submit to bluefin gateway
* @param marketAddress The address of the market/perpetual for which to adjust the margin
* @param amountE9 The amount to be added/withdrawn from isolated position
* @param options Optional params:
* - account: The account address for which margin to be adjusted. The account defaults to `this.walletAddress`
* - signer: The signer to be used to sign the payload. Defaults to signer of the class `this.signer`
* - salt: A random number to make the payload unique
* - ids: The internal data store id/address
* - signedAt: The timestamp in seconds at which the payload is signed
* @returns IRequestPayload
*/
async adjustMargin(market, add, amountE9, options) {
const signer = options?.signer || this.signer;
const account = options?.account || this.walletAddress;
const ids = options?.ids || this.parser.getInternalDataStore();
// build adjust margin request payload
const rawData = {
type: enums_1.PAYLOAD_REQUEST_TYPE.ADJUST_MARGIN,
ids,
account,
market,
add,
amount: (0, library_1.bigNumber)(amountE9).toFixed(0),
salt: String(options?.salt || (0, utils_1.generateSalt)()),
signedAt: String(options?.signedAt || Date.now())
};
// serialize the payload
const serializedData = bcs_1.BCSUtils.getSerializedDataHex(rawData, bcs_1.AdjustMargin);
// sign the payload
const signature = await utils_1.Signature.signRequest(signer, new TextEncoder().encode(JSON.stringify(rawData, null, 2)));
return { rawData, serializedData, signature };
}
/**
* Create a adjust leverage request for user to submit to bluefin gateway
* @param market The symbol of the market/perpetual for which to adjust the leverage
* @param leverage The new leverage to be used
* @param options Optional params:
* - account: The account address for which margin to be adjusted. The account defaults to `this.walletAddress`
* - signer: The signer to be used to sign the payload. Defaults to signer of the class `this.signer`
* - salt: A random number to make the payload unique
* - ids: The internal data store id/address
* - signedAt: The timestamp in seconds at which the payload is signed
* @returns IRequestPayload
*/
async adjustLeverage(market, leverage, options) {
const signer = options?.signer || this.signer;
const account = options?.account || this.walletAddress;
const ids = options?.ids || this.parser.getInternalDataStore();
// build adjust leverage request payload
const rawData = {
type: enums_1.PAYLOAD_REQUEST_TYPE.ADJUST_LEVERAGE,
ids,
account,
market,
leverage: (0, library_1.bigNumber)(leverage).toFixed(0),
salt: String(options?.salt || (0, utils_1.generateSalt)()),
signedAt: String(options?.signedAt || Date.now())
};
// serialize the payload
const serializedData = bcs_1.BCSUtils.getSerializedDataHex(rawData, bcs_1.AdjustLeverage);
// sign the payload
const signature = await utils_1.Signature.signRequest(signer, new TextEncoder().encode(JSON.stringify(rawData, null, 2)));
return { rawData, serializedData, signature };
}
/**
* Create a set funding rate request payload for the funding rate operator to submit to bluefin gateway
* @param marketsFundingRates The funding rate of each market/perpetual along with the market address
* @param options Optional params:
* - signer: The signer to be used to sign the payload. Defaults to signer of the class `this.signer`
* - salt: A random number to make the payload unique
* - timestamp: The timestamp in seconds for which the funding rate is being set.
* This should be hourly timestamp. If not provided the method takes current
* time and rounds it up/down to closest hour mark
* - ids: The internal data store id/address
* - signedAt: The timestamp in seconds at which the payload is signed
* @returns IRequestPayload
*/
async setFundingRate(marketsFundingRates, options) {
const signer = options?.signer || this.signer;
const ids = options?.ids || this.parser.getInternalDataStore();
const timestamp = options?.timestamp ||
new Date(3600000 * (1 + Math.round(Date.now() / 3600000))).getTime();
const fundingRates = marketsFundingRates.map(mfr => bcs_1.BCSUtils.getSerializedDataBytes(mfr, bcs_1.MarketFundingRate));
// build withdrawal request payload
const rawData = {
type: enums_1.PAYLOAD_REQUEST_TYPE.SET_FUNDING_RATE,
ids,
timestamp: String(timestamp),
marketFundingRates: fundingRates,
salt: String(options?.salt || (0, utils_1.generateSalt)()),
signedAt: String(options?.signedAt || Date.now())
};
// serialize the payload
const serializedData = bcs_1.BCSUtils.getSerializedDataHex(rawData, bcs_1.SetFundingRate);
// sign the payload
const signature = await utils_1.Signature.signRequest(signer, (0, library_1.hexStrToUint8)(serializedData));
return { rawData, serializedData, signature };
}
/**
* Create bcs serialized payload for applying funding rate
* @param accounts The array of account addresses to which to apply funding rate
* @param options Optional params:
* - ids: The address/id of the internal data store - This makes sure that a payload
* signed for testnet can not be executed on mainnet
* - salt: A random number to make the payload unique
* - timestamp: The timestamp in seconds for which the funding rate is to be applied
* This should be hourly timestamp. If not provided the method takes current
* time and rounds it up/down to closest hour mark
* - market: If provided, the FR request is created to be applied to provided market
* - signedAt: The timestamp in seconds at which the payload is signed
* @returns IRequestPayload
*/
async applyFundingRate(accounts, options) {
const timestamp = options?.timestamp ||
new Date(3600000 * (1 + Math.round(Date.now() / 3600000))).getTime() / 1000;
const ids = options?.ids || this.parser.getInternalDataStore();
const rawData = {
ids,
timestamp: String(timestamp),
accounts,
salt: String(options?.salt || (0, utils_1.generateSalt)()),
signedAt: String(options?.signedAt || Date.now()),
market: options?.market || ""
};
// serialize the payload
const serializedData = bcs_1.BCSUtils.getSerializedDataHex(rawData, bcs_1.ApplyFundingRate);
return { rawData, serializedData, signature: undefined };
}
/**
* Creates a prune table payload and signs it
* @param hashes The list of hashes that are to be pruned
* @param table_index The table type (index) from which the hashes are to be pruned
* @param options Optional params:
* - signer: The signer to be used to sign the payload. Defaults to signer of the class `this.signer`
* - salt: A random number to make the payload unique
* - ids: The address/id of the internal data store - This makes sure that a payload
* signed for testnet can not be executed on mainnet
* - signedAt: The timestamp in seconds at which the payload is signed
* @returns IRequestPayload
*/
async pruneTable(hashes, table_index, options) {
const signer = options?.signer || this.signer;
const ids = options?.ids || this.parser.getInternalDataStore();
// build withdrawal request payload
const rawData = {
type: enums_1.PAYLOAD_REQUEST_TYPE.PRUNING_TABLE,
ids,
hashes,
table_index,
salt: String(options?.salt || (0, utils_1.generateSalt)()),
signedAt: String(options?.signedAt || Date.now())
};
// serialize the payload
const serializedData = bcs_1.BCSUtils.getSerializedDataHex(rawData, bcs_1.PruneTable);
// sign the payload
const signature = await utils_1.Signature.signRequest(signer, (0, library_1.hexStrToUint8)(serializedData));
return { rawData, serializedData, signature };
}
/**
* Create an authorize bankrupt liquidator payload to submit to api gateway
* @param status The address of the account to be authorized or unauthorized
* @param authorized a boolean indicating if the users are to be authorized or not
* @param options Optional params:
* - signer: The signer that will be signing the payload
* - ids: The internal data store id
* - salt: A random number to make the payload unique
* - signedAt: The timestamp in seconds at which the payload is signed
* @returns IRequestPayload
*/
async authorizeLiquidator(account, authorized, options) {
const signer = options?.signer || this.signer;
const ids = options?.ids || this.parser.getInternalDataStore();
// build withdrawal request payload
const rawData = {
type: enums_1.PAYLOAD_REQUEST_TYPE.AUTHORIZE_LIQUIDATOR,
account,
ids: ids,
authorized,
salt: String(options?.salt || (0, utils_1.generateSalt)()),
signedAt: String(options?.signedAt || Date.now())
};
// serialize the payload
const serializedData = bcs_1.BCSUtils.getSerializedDataHex(rawData, bcs_1.authorizeLiquidator);
// sign the payload
const signature = await utils_1.Signature.signRequest(signer, (0, library_1.hexStrToUint8)(serializedData));
return { rawData, serializedData, signature };
}
/**
* Creates a signed payload for setting tier of an account
* @param status The address of the account to be authorized or unauthorized
* @param makerFee The maker side fee percentage
* @param takerFee The taker side fee percentage
* @param applied True if the fee tier is to be applied
* @param options Optional params:
* - signer: The signer that will be signing the payload
* - ids: The internal data store id
* - salt: A random number to make the payload unique
* - signedAt: The timestamp in seconds at which the payload is signed
* @returns IRequestPayload
*/
async setFeeTier(account, makerFee, takerFee, applied, options) {
const signer = options?.signer || this.signer;
const ids = options?.ids || this.parser.getInternalDataStore();
const makerFeeNumber = (0, library_1.bigNumber)(makerFee).toFixed(0);
const takerFeeNumber = (0, library_1.bigNumber)(takerFee).toFixed(0);
const rawData = {
type: enums_1.PAYLOAD_REQUEST_TYPE.SET_FEE_TIER,
account,
ids: ids,
makerFee: makerFeeNumber,
takerFee: takerFeeNumber,
applied,
salt: String(options?.salt || (0, utils_1.generateSalt)()),
signedAt: String(options?.signedAt || Date.now())
};
// serialize the payload
const serializedData = bcs_1.BCSUtils.getSerializedDataHex(rawData, bcs_1.FeeTier);
// sign the payload
const signature = await utils_1.Signature.signRequest(signer, (0, library_1.hexStrToUint8)(serializedData));
return { rawData, serializedData, signature };
}
/**
* Create a set account type signed payload
* @param account The address for which to set type
* @param type The account type Institution or Retail
* @param options Optional params:
* - signer: The signer that will be signing the payload
* - ids: The internal data store id
* - salt: A random number to make the payload unique
* - signedAt: The timestamp in seconds at which the payload is signed
* @returns IRequestPayload
*/
async setAccountType(account, type, options) {
const signer = options?.signer || this.signer;
const ids = options?.ids || this.parser.getInternalDataStore();
const rawData = {
type: enums_1.PAYLOAD_REQUEST_TYPE.SET_ACCOUNT_TYPE,
ids: ids,
account,
isInstitution: type == enums_1.ACCOUNT_TYPE.INSTITUTION,
salt: String(options?.salt || (0, utils_1.generateSalt)()),
signedAt: String(options?.signedAt || Date.now())
};
// serialize the payload
const serializedData = bcs_1.BCSUtils.getSerializedDataHex(rawData, bcs_1.AccountType);
// sign the payload
const signature = await utils_1.Signature.signRequest(signer, (0, library_1.hexStrToUint8)(serializedData));
return { rawData, serializedData, signature };
}
/**
* Create a set gas fee signed payload
* @param amount The new gas fee amount (in 1e9)
* @param options Optional params:
* - signer: The signer that will be signing the payload
* - ids: The internal data store id
* - salt: A random number to make the payload unique
* - signedAt: The timestamp in seconds at which the payload is signed
* @returns IRequestPayload
*/
async setGasFee(amount, options) {
const signer = options?.signer || this.signer;
const ids = options?.ids || this.parser.getInternalDataStore();
const rawData = {
type: enums_1.PAYLOAD_REQUEST_TYPE.SET_GAS_FEE,
ids: ids,
amount: (0, library_1.bigNumber)(amount).toFixed(0),
salt: String(options?.salt || (0, utils_1.generateSalt)()),
signedAt: String(options?.signedAt || Date.now())
};
// serialize the payload
const serializedData = bcs_1.BCSUtils.getSerializedDataHex(rawData, bcs_1.GasFee);
// sign the payload
const signature = await utils_1.Signature.signRequest(signer, (0, library_1.hexStrToUint8)(serializedData));
return { rawData, serializedData, signature };
}
/**
* Create a set gas pool signed payload
* @param pool The new gas pool address
* @param options Optional params:
* - signer: The signer that will be signing the payload
* - ids: The internal data store id
* - salt: A random number to make the payload unique
* - signedAt: The timestamp in seconds at which the payload is signed
* @returns IRequestPayload
*/
async setGasPool(pool, options) {
const signer = options?.signer || this.signer;
const ids = options?.ids || this.parser.getInternalDataStore();
const rawData = {
type: enums_1.PAYLOAD_REQUEST_TYPE.SET_GAS_POOL,
ids: ids,
pool,
salt: String(options?.salt || (0, utils_1.generateSalt)()),
signedAt: String(options?.signedAt || Date.now())
};
// serialize the payload
const serializedData = bcs_1.BCSUtils.getSerializedDataHex(rawData, bcs_1.GasPool);
// sign the payload
const signature = await utils_1.Signature.signRequest(signer, (0, library_1.hexStrToUint8)(serializedData));
return { rawData, serializedData, signature };
}
/**
* Create signed payload for closing position of a delisted market
* @param market Market name for which to close the position
* @param positionType The type of position being closed ISOLATED or CROSS
* @param options Optional params:
* - account: The address of the account for which the position is being closed
* - signer: The signer that will be signing the payload
* - ids: The internal data store id
* - salt: A random number to make the payload unique
* - signedAt: The timestamp in seconds at which the payload is signed
* @returns IRequestPayload
*/
async closePosition(market, positionType, options) {
const signer = options?.signer || this.signer;
const ids = options?.ids || this.parser.getInternalDataStore();
const account = options?.account || signer.toSuiAddress();
const rawData = {
type: enums_1.PAYLOAD_REQUEST_TYPE.CLOSE_POSITION,
ids: ids,
account,
market,
isolated: positionType == enums_1.POSITION_TYPES.ISOLATED,
salt: String(options?.salt || (0, utils_1.generateSalt)()),
signedAt: String(options?.signedAt || Date.now())
};
// serialize the payload
const serializedData = bcs_1.BCSUtils.getSerializedDataHex(rawData, bcs_1.ClosePosition);
// sign the payload
const signature = await utils_1.Signature.signRequest(signer, new TextEncoder().encode(JSON.stringify(rawData, null, 2)));
return { rawData, serializedData, signature };
}
}
exports.RequestsBuilder = RequestsBuilder;