@firefly-exchange/library-sui
Version:
Sui library housing helper methods, classes to interact with Bluefin protocol(s) deployed on Sui
344 lines (343 loc) • 14.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.OnChainCalls = void 0;
const utils_1 = require("@mysten/sui/utils");
const classes_1 = require("../classes");
const library_1 = require("../library");
const clmm_1 = require("../spot/clmm");
const types_1 = require("../types");
class OnChainCalls {
constructor(_suiClient, _contracts, options) {
this.suiClient = _suiClient;
this.contracts = _contracts;
this.spotContracts = options?.spotContracts;
this.signerConfig = {
signer: options?.signer,
address: options?.address || options?.signer?.toSuiAddress(),
isUIWallet: options?.isUIWallet == true
};
}
/**
* Returns the vaults of provided name
* @param name Name of the vault(s) to look for
* @returns Array of vaults
*/
getVaultByName(name) {
return this.contracts.Vaults.filter(vault => vault.name == name);
}
/**
* Fetches the state of vault from chain
* @param id
* @returns
*/
async getVaultFromChain(id) {
const vault = await this.suiClient.getObject({
id,
options: { showContent: true }
});
const fields = (vault.data?.content).fields;
delete fields.id;
fields.id = id;
return fields;
}
/**
* Returns all positions opened using the funds of provided vault
* @param vault The id of the vault
* @returns array of positions
*/
async getVaultPositions(vault) {
const dynamicFieldObject = await this.suiClient.getDynamicFieldObject({
parentId: vault,
name: {
type: "0x1::string::String",
value: "positions"
}
});
const vector = (dynamicFieldObject.data?.content).fields.value;
return vector.map(v => {
return {
owner: vault,
pool_id: v.fields.pool_id,
position_id: v.fields.id.id,
lower_tick: Number((0, clmm_1.asIntN)(BigInt(v.fields.lower_tick.fields.bits)).toString()),
upper_tick: Number((0, clmm_1.asIntN)(BigInt(v.fields.upper_tick.fields.bits)).toString()),
liquidity: Number(v.fields.liquidity),
fee_growth_coin_a: Number(v.fields.fee_growth_coin_a),
fee_growth_coin_b: Number(v.fields.fee_growth_coin_b),
fee_rate: Number(v.fields.fee_rate),
token_a_fee: Number(v.fields.token_a_fee),
token_b_fee: Number(v.fields.token_b_fee)
};
});
}
/**
* Returns the current available reserves of each token that vault holds
* @param vault The id of the vault
* @returns Array of coin reserves
*/
async getVaultReserves(vault) {
let cursor = undefined;
let hasNextPage = true;
let dynamicFields = [];
while (hasNextPage) {
const resp = await this.suiClient.getDynamicFields({
parentId: vault
});
hasNextPage = resp.hasNextPage;
cursor = resp.nextCursor;
dynamicFields = dynamicFields.concat(resp.data);
}
const reserves = await Promise.all(dynamicFields
.filter(df => df.name.value != "positions")
.map(async (df) => {
const dynamicFieldObject = await this.suiClient.getDynamicFieldObject({
parentId: vault,
name: df.name
});
const fields = (dynamicFieldObject.data?.content).fields;
return {
id: fields.id.id,
coinType: fields.name,
value: Number(fields.value)
};
}));
return reserves;
}
/**
* @notice Allows caller to create a vault. Any one is allowed to create a vault.
* @param args CreateVaultArgs
* @param options: OnChain params call
* Returns OnChainCallResponse
*/
async createVault(args, options) {
const txBlock = options?.txb || new types_1.TransactionBlock();
txBlock.moveCall({
arguments: [
txBlock.object(this.contracts.ProtocolConfig),
txBlock.object(this.contracts.VaultStore),
txBlock.pure.address(args.manager || this.signerConfig.address),
txBlock.pure.string(args.name),
txBlock.pure.u8(args.type || 1),
txBlock.pure.vector("address", args.users || [])
],
target: `${this.contracts.CurrentPackage}::vault::create_vault`
});
return this.setAndExecute(txBlock, options);
}
/**
* @notice Allows caller to deposit funds into the vault for its users to use
* @param args FundVaultArgs
* @param options: OnChain params call
* Returns OnChainCallResponse
*/
async provideFunds(args, options) {
const txBlock = options?.txb || new types_1.TransactionBlock();
// create coin of provided balance
const [splitCoin, mergeCoin] = await classes_1.CoinUtils.createCoinWithBalance(this.suiClient, txBlock, args.amount, args.coinType, this.signerConfig.address);
txBlock.moveCall({
arguments: [
txBlock.object(this.contracts.ProtocolConfig),
txBlock.object(args.vault),
txBlock.object(splitCoin)
],
target: `${this.contracts.CurrentPackage}::vault::provide_funds`,
typeArguments: [args.coinType]
});
if (mergeCoin) {
txBlock.transferObjects([mergeCoin], this.signerConfig.address);
}
return this.setAndExecute(txBlock, options);
}
/**
* @notice Allows vault manager to withdraw funds from the vault
* @param args WithdrawFundArgs
* @param options: OnChain params call
* Returns OnChainCallResponse
*/
async withdrawFunds(args, options) {
const txBlock = options?.txb || new types_1.TransactionBlock();
txBlock.moveCall({
arguments: [
txBlock.object(this.contracts.ProtocolConfig),
txBlock.object(args.vault),
txBlock.pure.u64((0, library_1.bigNumber)(args.amount).toFixed(0))
],
target: `${this.contracts.CurrentPackage}::vault::withdraw_funds`,
typeArguments: [args.coinType]
});
return this.setAndExecute(txBlock, options);
}
/**
* @notice Allows vault manager to add/whitelist or remove/blacklist users from the vault
* @param args UpdateUsersArgs
* @param options: OnChain params call
* Returns OnChainCallResponse
*/
async updateUsers(args, options) {
const txBlock = options?.txb || new types_1.TransactionBlock();
txBlock.moveCall({
arguments: [
txBlock.object(this.contracts.ProtocolConfig),
txBlock.object(args.vault),
txBlock.pure.vector("address", args.users)
],
target: `${this.contracts.CurrentPackage}::vault::${args.add ? "add_users" : "remove_users"}`
});
return this.setAndExecute(txBlock, options);
}
/**
* Allows caller to open a position for the provided pool for given ticks
* using the specified vault funds
* @param args OpenPositionArgs
* @param options IOnChainCallOptionalParams
* @returns Onchain call response
*/
async openPosition(args, options) {
const txBlock = options?.txb || new types_1.TransactionBlock();
txBlock.moveCall({
arguments: [
txBlock.object(this.contracts.ProtocolConfig),
txBlock.object(args.vault),
txBlock.object(this.spotContracts.GlobalConfig),
txBlock.object(args.pool.id),
txBlock.pure.u32(args.lowerTickBits),
txBlock.pure.u32(args.upperTickBits)
],
target: `${this.contracts.CurrentPackage}::spot::open_position`,
typeArguments: [args.pool.coin_a.address, args.pool.coin_b.address]
});
return this.setAndExecute(txBlock, options);
}
/**
* Allows caller to provide liquidity to a position opened using the vault on bluefin spot protocol
* @param args Provide liquidity arguments
* @param options IOnChainCallOptionalParams
* @returns Onchain call response
*/
async provideLiquidity(args, options) {
const txBlock = options?.txb || new types_1.TransactionBlock();
txBlock.moveCall({
arguments: [
txBlock.object(utils_1.SUI_CLOCK_OBJECT_ID),
txBlock.object(this.contracts.ProtocolConfig),
txBlock.object(args.vault),
txBlock.object(this.spotContracts.GlobalConfig),
txBlock.object(args.pool.id),
txBlock.pure.id(args.position),
txBlock.pure.u64((0, library_1.bigNumber)(args.amount).toFixed(0)),
txBlock.pure.u64((0, library_1.bigNumber)(args.coinAMax).toFixed(0)),
txBlock.pure.u64((0, library_1.bigNumber)(args.coinBMax).toFixed(0)),
txBlock.pure.bool(args.isFixedA)
],
target: `${this.contracts.CurrentPackage}::spot::provide_liquidity_with_fixed_amount`,
typeArguments: [args.pool.coin_a.address, args.pool.coin_b.address]
});
return this.setAndExecute(txBlock, options);
}
/**
* Allows caller to remove liquidity from a position opened using the vault on bluefin spot protocol
* @param args Remove liquidity arguments
* @param options IOnChainCallOptionalParams
* @returns Onchain call response
*/
async removeLiquidity(args, options) {
const txBlock = options?.txb || new types_1.TransactionBlock();
txBlock.moveCall({
arguments: [
txBlock.object(utils_1.SUI_CLOCK_OBJECT_ID),
txBlock.object(this.contracts.ProtocolConfig),
txBlock.object(args.vault),
txBlock.object(this.spotContracts.GlobalConfig),
txBlock.object(args.pool.id),
txBlock.pure.id(args.position),
txBlock.pure.u128((0, library_1.bigNumber)(args.liquidity).toFixed(0)),
txBlock.pure.u64((0, library_1.bigNumber)(args.coinAMin).toFixed(0)),
txBlock.pure.u64((0, library_1.bigNumber)(args.coinBMin).toFixed(0))
],
target: `${this.contracts.CurrentPackage}::spot::remove_liquidity`,
typeArguments: [args.pool.coin_a.address, args.pool.coin_b.address]
});
return this.setAndExecute(txBlock, options);
}
/**
* Allows caller to collect any fee accrued in the position opened on bluefin spot pools using vault funds
* @param args Collect Fee Arguments
* @param options IOnChainCallOptionalParams
* @returns Onchain call response
*/
async collectFee(args, options) {
const txBlock = options?.txb || new types_1.TransactionBlock();
txBlock.moveCall({
arguments: [
txBlock.object(utils_1.SUI_CLOCK_OBJECT_ID),
txBlock.object(this.contracts.ProtocolConfig),
txBlock.object(args.vault),
txBlock.object(this.spotContracts.GlobalConfig),
txBlock.object(args.pool.id),
txBlock.pure.id(args.position),
txBlock.pure.address(args.destination)
],
target: `${this.contracts.CurrentPackage}::spot::collect_fee`,
typeArguments: [args.pool.coin_a.address, args.pool.coin_b.address]
});
return this.setAndExecute(txBlock, options);
}
/**
* Allows caller to collect the rewards accrued of given coin type on a position opened on bluefin spot pools
* @param args Collect Reward Arguments
* @param options IOnChainCallOptionalParams
* @returns Onchain call response
*/
async collectReward(args, options) {
const txBlock = options?.txb || new types_1.TransactionBlock();
txBlock.moveCall({
arguments: [
txBlock.object(utils_1.SUI_CLOCK_OBJECT_ID),
txBlock.object(this.contracts.ProtocolConfig),
txBlock.object(args.vault),
txBlock.object(this.spotContracts.GlobalConfig),
txBlock.object(args.pool.id),
txBlock.pure.id(args.position),
txBlock.pure.address(args.destination)
],
target: `${this.contracts.CurrentPackage}::spot::collect_reward`,
typeArguments: [
args.pool.coin_a.address,
args.pool.coin_b.address,
args.rewardCoinType
]
});
return this.setAndExecute(txBlock, options);
}
/**
* Allows caller to close a position on bluefin spot protocol
* @param args Close Position Arguments
* @param options IOnChainCallOptionalParams
* @returns Onchain call response
*/
async closePosition(args, options) {
const txBlock = options?.txb || new types_1.TransactionBlock();
txBlock.moveCall({
arguments: [
txBlock.object(utils_1.SUI_CLOCK_OBJECT_ID),
txBlock.object(this.contracts.ProtocolConfig),
txBlock.object(args.vault),
txBlock.object(this.spotContracts.GlobalConfig),
txBlock.object(args.pool.id),
txBlock.pure.id(args.position),
txBlock.pure.address(args.destination)
],
target: `${this.contracts.CurrentPackage}::spot::close_position`,
typeArguments: [args.pool.coin_a.address, args.pool.coin_b.address]
});
return this.setAndExecute(txBlock, options);
}
async setAndExecute(txBlock, options) {
if (options?.gasBudget)
txBlock.setGasBudget(options.gasBudget);
if (options?.sender)
txBlock.setSenderIfNotSet(options.sender);
return classes_1.SuiBlocks.execCall(txBlock, this.suiClient, this.signerConfig.signer, options?.dryRun, this.signerConfig.isUIWallet);
}
}
exports.OnChainCalls = OnChainCalls;