@scallop-io/scallop-deepbook-kit 0.1.6 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _mysten_deepbook_v3 from '@mysten/deepbook-v3';
2
- import { DeepBookConfig, MarginPoolContract } from '@mysten/deepbook-v3';
2
+ import { DeepBookConfig, MarginPoolContract, Coin } from '@mysten/deepbook-v3';
3
3
  import { SuiClient } from '@mysten/sui/client';
4
4
  import { Transaction } from '@mysten/sui/transactions';
5
5
 
@@ -62,14 +62,8 @@ type InterestConfig = {
62
62
  supplyApr: number;
63
63
  utilizationRate: number;
64
64
  };
65
- type MarginPoolParams = Record<MarginPoolParamKey | MarginPoolWithSupplierCapParamKey, number> & InterestConfig & {
66
- address: string;
67
- type: string;
68
- scalar: number;
65
+ type MarginPoolParams = Record<MarginPoolParamKey | MarginPoolWithSupplierCapParamKey, number> & InterestConfig & Coin & {
69
66
  decimals: number;
70
- feed: string;
71
- currencyId: string;
72
- priceInfoObjectId: string;
73
67
  };
74
68
  type DeepBookMarginPoolParams = {
75
69
  address?: string;
@@ -84,6 +78,10 @@ declare class DeepBookMarginPool {
84
78
  suiClient: SuiClient;
85
79
  constructor({ env, address, suiClient, dbConfig, }?: DeepBookMarginPoolParams);
86
80
  get env(): _mysten_deepbook_v3.Environment;
81
+ private parseInspectResultToBcsStructs;
82
+ private formatResult;
83
+ private computeBorrowAprAtUtil;
84
+ private calculateKinksAndRate;
87
85
  getPoolParameters(coinKey: string, supplierCapId?: string, tx?: Transaction): Promise<MarginPoolParams>;
88
86
  getPoolParameters(coinKey: string, supplierCapId: string | undefined, tx: Transaction, inspect: true): Promise<MarginPoolParams>;
89
87
  getPoolParameters(coinKey: string, supplierCapId: string | undefined, tx: Transaction, inspect: false): Promise<Transaction>;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _mysten_deepbook_v3 from '@mysten/deepbook-v3';
2
- import { DeepBookConfig, MarginPoolContract } from '@mysten/deepbook-v3';
2
+ import { DeepBookConfig, MarginPoolContract, Coin } from '@mysten/deepbook-v3';
3
3
  import { SuiClient } from '@mysten/sui/client';
4
4
  import { Transaction } from '@mysten/sui/transactions';
5
5
 
@@ -62,14 +62,8 @@ type InterestConfig = {
62
62
  supplyApr: number;
63
63
  utilizationRate: number;
64
64
  };
65
- type MarginPoolParams = Record<MarginPoolParamKey | MarginPoolWithSupplierCapParamKey, number> & InterestConfig & {
66
- address: string;
67
- type: string;
68
- scalar: number;
65
+ type MarginPoolParams = Record<MarginPoolParamKey | MarginPoolWithSupplierCapParamKey, number> & InterestConfig & Coin & {
69
66
  decimals: number;
70
- feed: string;
71
- currencyId: string;
72
- priceInfoObjectId: string;
73
67
  };
74
68
  type DeepBookMarginPoolParams = {
75
69
  address?: string;
@@ -84,6 +78,10 @@ declare class DeepBookMarginPool {
84
78
  suiClient: SuiClient;
85
79
  constructor({ env, address, suiClient, dbConfig, }?: DeepBookMarginPoolParams);
86
80
  get env(): _mysten_deepbook_v3.Environment;
81
+ private parseInspectResultToBcsStructs;
82
+ private formatResult;
83
+ private computeBorrowAprAtUtil;
84
+ private calculateKinksAndRate;
87
85
  getPoolParameters(coinKey: string, supplierCapId?: string, tx?: Transaction): Promise<MarginPoolParams>;
88
86
  getPoolParameters(coinKey: string, supplierCapId: string | undefined, tx: Transaction, inspect: true): Promise<MarginPoolParams>;
89
87
  getPoolParameters(coinKey: string, supplierCapId: string | undefined, tx: Transaction, inspect: false): Promise<Transaction>;
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- 'use strict';var client=require('@mysten/sui/client'),ed25519=require('@mysten/sui/keypairs/ed25519'),transactions=require('@mysten/sui/transactions'),deepbookV3=require('@mysten/deepbook-v3'),cryptography=require('@mysten/sui/cryptography'),bcs$1=require('@mysten/bcs'),bcs=require('@mysten/sui/bcs'),bignumber_js=require('bignumber.js');var K=a=>/^0x[0-9a-fA-F]+$|^[0-9a-fA-F]+$/.test(a),B=a=>/^[a-zA-Z0-9+/]+={0,2}$/g.test(a),S=a=>{if(K(a))return bcs$1.fromHex(a);if(B(a))return bcs$1.fromBase64(a);throw new Error("The string is not a valid hex or base64 string.")},f=a=>{if(a.length===cryptography.LEGACY_PRIVATE_KEY_SIZE)return a.slice(0,cryptography.PRIVATE_KEY_SIZE);if(a.length===cryptography.PRIVATE_KEY_SIZE+1&&a[0]===0)return a.slice(1);if(a.length===cryptography.PRIVATE_KEY_SIZE)return a;throw new Error("invalid secret key")};var C=class{suiClient;keypair;address;marginPoolContract;supplierCapId;dbConfig;supplierCapPackageId;constructor({network:r,fullnodeUrl:e,supplierCapId:t,privateKey:i,supplierCapPackageId:o,dbConfig:n}){let s=e??client.getFullnodeUrl(r);this.suiClient=new client.SuiClient({url:s}),this.keypair=this.#r(i),this.address=this.keypair.getPublicKey().toSuiAddress(),this.supplierCapId=t,this.dbConfig=n??new deepbookV3.DeepBookConfig({env:r,address:this.address}),this.marginPoolContract=new deepbookV3.MarginPoolContract(this.dbConfig),this.supplierCapPackageId=o??this.dbConfig.MARGIN_PACKAGE_ID;}#r(r){if(r.startsWith(cryptography.SUI_PRIVATE_KEY_PREFIX)){let{secretKey:e}=cryptography.decodeSuiPrivateKey(r);return ed25519.Ed25519Keypair.fromSecretKey(f(e))}return ed25519.Ed25519Keypair.fromSecretKey(f(S(r)))}async#t(){let r=`${this.dbConfig.MARGIN_PACKAGE_ID}::margin_pool::SupplierCap`;return (await this.suiClient.getOwnedObjects({owner:this.address,filter:{StructType:r},options:{showType:true}})).data?.[0]?.data?.objectId}async initialize(){if(this.supplierCapId)return this.supplierCapId;let r=await this.#t();if(r)return this.supplierCapId=r,r;let e=await this.createSupplierCap();if(!e)throw new Error("Failed to create Supplier Cap");return this.supplierCapId=e,e}async createSupplierCap(){try{let r=new transactions.Transaction;r.setSender(this.address);let e=r.moveCall({target:`${this.supplierCapPackageId}::margin_pool::mint_supplier_cap`,arguments:[r.object(this.dbConfig.MARGIN_REGISTRY_ID),r.object.clock()]});r.transferObjects([e],r.pure.address(this.address));let t=await this.suiClient.signAndExecuteTransaction({signer:this.keypair,transaction:r,options:{showEffects:!0,showObjectChanges:!0}});if(t.errors&&t.errors.length>0)throw new Error(`Transaction failed with errors: ${t.errors.map(i=>i.toString()).join(", ")}`);if(t.objectChanges){for(let i of t.objectChanges)if(i.type==="created"&&i.objectType.includes("SupplierCap"))return i.objectId}return null}catch(r){throw new Error(`Failed to create Supplier Cap: ${r.message||r}`)}}async createSupplyReferral(r){try{let e=new transactions.Transaction;e.setSender(this.address);let t=this.dbConfig.getMarginPool(r);if(!t)throw new Error(`Margin pool configuration not found for coin: ${r}`);e.moveCall({target:`${this.dbConfig.MARGIN_PACKAGE_ID}::margin_pool::mint_supply_referral`,arguments:[e.object(t.address),e.object(this.dbConfig.MARGIN_REGISTRY_ID),e.object.clock()],typeArguments:[t.type]});let i=await this.suiClient.signAndExecuteTransaction({signer:this.keypair,transaction:e,options:{showEffects:!0,showObjectChanges:!0}});if(i.errors&&i.errors.length>0)throw new Error(`Transaction failed with errors: ${i.errors.map(o=>o.toString()).join(", ")}`);if(i.objectChanges){for(let o of i.objectChanges)if(o.type==="created"&&o.objectType.includes("SupplyReferral"))return o.objectId}return null}catch(e){throw new Error(`Failed to create Supply Referral: ${e.message||e}`)}}async supplyToMarginPool(r,e,t){try{if(!this.supplierCapId)throw new Error("Supplier Cap not initialized. Call initialize() first.");let i=new transactions.Transaction;i.setSender(this.address);let o=i.object(this.supplierCapId);i.add(this.marginPoolContract.supplyToMarginPool(r,o,e,t));let{errors:n}=await this.suiClient.signAndExecuteTransaction({signer:this.keypair,transaction:i,options:{showEffects:!0,showObjectChanges:!0}});if(n&&n.length>0)throw new Error(`Transaction failed with errors: ${n.map(s=>s.toString()).join(", ")}`);return !0}catch(i){throw new Error(`Failed to supply to margin pool: ${i.message||i}`)}}async withdrawFromMarginPool(r,e){try{if(!this.supplierCapId)throw new Error("Supplier Cap not initialized. Call initialize() first.");let t=new transactions.Transaction,i=t.object(this.supplierCapId),n=this.marginPoolContract.withdrawFromMarginPool(r,i,e)(t);t.transferObjects([n],this.address);let{errors:s}=await this.suiClient.signAndExecuteTransaction({signer:this.keypair,transaction:t,options:{showEffects:!0,showObjectChanges:!0}});if(s&&s.length>0)throw new Error(`Transaction failed with errors: ${s.map(l=>l.toString()).join(", ")}`);return !0}catch(t){throw new Error(`Failed to withdraw from margin pool: ${t.message||t}`)}}async withdrawReferralFees(r,e){try{let t=new transactions.Transaction;t.add(this.marginPoolContract.withdrawReferralFees(r,e));let{errors:i}=await this.suiClient.signAndExecuteTransaction({signer:this.keypair,transaction:t,options:{showEffects:!0,showObjectChanges:!0,showBalanceChanges:!0}});if(i&&i.length>0)throw new Error(`Transaction failed with errors: ${i.map(o=>o.toString()).join(", ")}`);return !0}catch(t){throw new Error(`Failed to withdraw referral fees: ${t.message||t}`)}}async getBalance(r){try{if(!this.supplierCapId)throw new Error("Supplier Cap not initialized. Call initialize() first.");let e=new transactions.Transaction;e.add(this.marginPoolContract.userSupplyAmount(r,this.supplierCapId));let t=await this.suiClient.devInspectTransactionBlock({sender:this.address,transactionBlock:e}),i=0;if(t&&t.results&&t.results[0]&&t.results[0].returnValues){let p=t.results[0].returnValues[0];if(p&&p[0]){let g=Buffer.from(p[0]).readBigUInt64LE(),R=this.dbConfig.getCoin(r).scalar;i=Number(g)/R;}}let o=this.dbConfig.getCoin(r).type,n=await this.suiClient.getBalance({owner:this.address,coinType:o}),s=this.dbConfig.getCoin(r).scalar,l=Number(n.totalBalance)/s;return {userSupplyAmount:i,walletBalance:l}}catch(e){throw new Error(`Failed to get balance: ${e.message||e}`)}}getSupplierCapId(){return this.supplierCapId}getAddress(){return this.address}};var P=["supplyCap","maxUtilizationRate","protocolSpread","minBorrow","interestRate","totalSupply","supplyShares","totalBorrow","borrowShares","lastUpdateTimestamp"],m=["userSupplyShares","userSupplyAmount"],A={supplyCap:"U64",maxUtilizationRate:"U64",protocolSpread:"U64",minBorrow:"U64",interestRate:"U64",totalSupply:"U64",supplyShares:"U64",totalBorrow:"U64",borrowShares:"U64",lastUpdateTimestamp:"U64",userSupplyShares:"U64",userSupplyAmount:"U64"};var d=(a,r)=>a*r/BigInt(deepbookV3.FLOAT_SCALAR),c=a=>Number(a)/deepbookV3.FLOAT_SCALAR;var W=new Set(m),Y=a=>W.has(a),b=class{marginPoolContract;dbConfig;suiClient;constructor({env:r="mainnet",address:e="",suiClient:t=new client.SuiClient({url:client.getFullnodeUrl(r)}),dbConfig:i=new deepbookV3.DeepBookConfig({env:r,address:e})}={}){if(this.dbConfig=i,this.suiClient=t,this.marginPoolContract=new deepbookV3.MarginPoolContract(this.dbConfig),r!==this.env)throw new Error(`Mismatch between provided env (${r}) and dbConfig env (${this.env}).`)}get env(){return this.dbConfig.env}#r(r,e,t,i){if(Y(e)){let o=this.marginPoolContract[e];if(i==null)throw new Error(`supplierCap is required for '${e}'.`);r.add(o(t,i));}else {let o=this.marginPoolContract[e];r.add(o(t));}}#t(r,e){let t=r.results;return t?e.reduce((i,o,n)=>{let s=t[n]?.returnValues?.[0]?.[0];if(!s)return i;let l=bcs.bcs[A[o]];return i[o]=l.parse(new Uint8Array(s)),i},{}):{}}#i(r,e){let t=this.dbConfig.getCoin(e),i={supplyCap:0,maxUtilizationRate:0,protocolSpread:0,minBorrow:0,interestRate:0,totalSupply:0,supplyShares:0,totalBorrow:0,borrowShares:0,lastUpdateTimestamp:0,userSupplyShares:0,userSupplyAmount:0,decimals:this.dbConfig.getCoin(e).scalar.toString().length-1,highKink:0,baseBorrowApr:0,borrowAprOnHighKink:0,maxBorrowApr:0,supplyApr:0,utilizationRate:0,feed:"",currencyId:"",priceInfoObjectId:"",...t};if(!t)return i;let o=new Set(["interestRate","maxUtilizationRate","protocolSpread"]);for(let[n,s]of Object.entries(r))n==="lastUpdateTimestamp"?i[n]=Number(s):o.has(n)?i[n]=new bignumber_js.BigNumber(s).dividedBy(deepbookV3.FLOAT_SCALAR).toNumber():i[n]=new bignumber_js.BigNumber(s).dividedBy(t.scalar).toNumber();return i}#e(r,e){let t=BigInt(e.base_rate),i=BigInt(e.base_slope),o=BigInt(e.excess_slope),n=BigInt(e.optimal_utilization);return r<n?t+d(r,i):t+d(n,i)+d(r-n,o)}#o(r,e,t,i){let o=BigInt(r.optimal_utilization),n=BigInt(e.max_utilization_rate),s=this.#e(o,r),l=this.#e(n,r),p=BigInt(bignumber_js.BigNumber(t.total_borrow).dividedBy(t.total_supply).shiftedBy(9).decimalPlaces(0).toString()),g=d(d(BigInt(i),p),BigInt(deepbookV3.FLOAT_SCALAR)-BigInt(e.protocol_spread));return {raw:{baseBorrowApr:r.base_rate,highKink:o,borrowAprOnHighKink:s,maxBorrowApr:l,supplyApr:g,utilizationRate:p},normalized:{baseBorrowApr:c(BigInt(r.base_rate)),highKink:c(o),borrowAprOnHighKink:c(s),maxBorrowApr:c(l),supplyApr:c(g),utilizationRate:c(p)}}}async#n(r,e){let{address:t}=this.dbConfig.getMarginPool(r),o=((await this.suiClient.getObject({id:t,options:{showContent:true}})).data?.content).fields,n=o.config.fields,s=n.interest_config.fields,l=n.margin_pool_config.fields,p=o.state.fields,{normalized:g}=this.#o(s,l,p,e);return g}async getPoolParameters(r,e,t=new transactions.Transaction,i=true){if(P.forEach(p=>this.#r(t,p,r)),e&&m.forEach(p=>this.#r(t,p,r,e)),!i)return t;let o=[...P,...m],n=await this.suiClient.devInspectTransactionBlock({transactionBlock:t,sender:this.dbConfig.address}),s=this.#i(this.#t(n,o),r),l=await this.#n(r,s.interestRate*deepbookV3.FLOAT_SCALAR);return {...s,...l}}};exports.DeepBookMarginPool=b;exports.DeepBookMarginToolkit=C;
1
+ 'use strict';var client=require('@mysten/sui/client'),ed25519=require('@mysten/sui/keypairs/ed25519'),transactions=require('@mysten/sui/transactions'),deepbookV3=require('@mysten/deepbook-v3'),cryptography=require('@mysten/sui/cryptography'),bcs$1=require('@mysten/bcs'),bcs=require('@mysten/sui/bcs'),bignumber_js=require('bignumber.js');var T=n=>/^0x[0-9a-fA-F]+$|^[0-9a-fA-F]+$/.test(n),B=n=>/^[a-zA-Z0-9+/]+={0,2}$/g.test(n),A=n=>{if(T(n))return bcs$1.fromHex(n);if(B(n))return bcs$1.fromBase64(n);throw new Error("The string is not a valid hex or base64 string.")},C=n=>{if(n.length===cryptography.LEGACY_PRIVATE_KEY_SIZE)return n.slice(0,cryptography.PRIVATE_KEY_SIZE);if(n.length===cryptography.PRIVATE_KEY_SIZE+1&&n[0]===0)return n.slice(1);if(n.length===cryptography.PRIVATE_KEY_SIZE)return n;throw new Error("invalid secret key")};var P=class{suiClient;keypair;address;marginPoolContract;supplierCapId;dbConfig;supplierCapPackageId;constructor({network:r,fullnodeUrl:e,supplierCapId:t,privateKey:i,supplierCapPackageId:o,dbConfig:a}){let s=e??client.getFullnodeUrl(r);this.suiClient=new client.SuiClient({url:s}),this.keypair=this.#r(i),this.address=this.keypair.getPublicKey().toSuiAddress(),this.supplierCapId=t,this.dbConfig=a??new deepbookV3.DeepBookConfig({env:r,address:this.address}),this.marginPoolContract=new deepbookV3.MarginPoolContract(this.dbConfig),this.supplierCapPackageId=o??this.dbConfig.MARGIN_PACKAGE_ID;}#r(r){if(r.startsWith(cryptography.SUI_PRIVATE_KEY_PREFIX)){let{secretKey:e}=cryptography.decodeSuiPrivateKey(r);return ed25519.Ed25519Keypair.fromSecretKey(C(e))}return ed25519.Ed25519Keypair.fromSecretKey(C(A(r)))}async#t(){let r=`${this.dbConfig.MARGIN_PACKAGE_ID}::margin_pool::SupplierCap`;return (await this.suiClient.getOwnedObjects({owner:this.address,filter:{StructType:r},options:{showType:true}})).data?.[0]?.data?.objectId}async initialize(){if(this.supplierCapId)return this.supplierCapId;let r=await this.#t();if(r)return this.supplierCapId=r,r;let e=await this.createSupplierCap();if(!e)throw new Error("Failed to create Supplier Cap");return this.supplierCapId=e,e}async createSupplierCap(){try{let r=new transactions.Transaction;r.setSender(this.address);let e=r.moveCall({target:`${this.supplierCapPackageId}::margin_pool::mint_supplier_cap`,arguments:[r.object(this.dbConfig.MARGIN_REGISTRY_ID),r.object.clock()]});r.transferObjects([e],r.pure.address(this.address));let t=await this.suiClient.signAndExecuteTransaction({signer:this.keypair,transaction:r,options:{showEffects:!0,showObjectChanges:!0}});if(t.errors&&t.errors.length>0)throw new Error(`Transaction failed with errors: ${t.errors.map(i=>i.toString()).join(", ")}`);if(t.objectChanges){for(let i of t.objectChanges)if(i.type==="created"&&i.objectType.includes("SupplierCap"))return i.objectId}return null}catch(r){throw new Error(`Failed to create Supplier Cap: ${r.message||r}`)}}async createSupplyReferral(r){try{let e=new transactions.Transaction;e.setSender(this.address);let t=this.dbConfig.getMarginPool(r);if(!t)throw new Error(`Margin pool configuration not found for coin: ${r}`);e.moveCall({target:`${this.dbConfig.MARGIN_PACKAGE_ID}::margin_pool::mint_supply_referral`,arguments:[e.object(t.address),e.object(this.dbConfig.MARGIN_REGISTRY_ID),e.object.clock()],typeArguments:[t.type]});let i=await this.suiClient.signAndExecuteTransaction({signer:this.keypair,transaction:e,options:{showEffects:!0,showObjectChanges:!0}});if(i.errors&&i.errors.length>0)throw new Error(`Transaction failed with errors: ${i.errors.map(o=>o.toString()).join(", ")}`);if(i.objectChanges){for(let o of i.objectChanges)if(o.type==="created"&&o.objectType.includes("SupplyReferral"))return o.objectId}return null}catch(e){throw new Error(`Failed to create Supply Referral: ${e.message||e}`)}}async supplyToMarginPool(r,e,t){try{if(!this.supplierCapId)throw new Error("Supplier Cap not initialized. Call initialize() first.");let i=new transactions.Transaction;i.setSender(this.address);let o=i.object(this.supplierCapId);i.add(this.marginPoolContract.supplyToMarginPool(r,o,e,t));let{errors:a}=await this.suiClient.signAndExecuteTransaction({signer:this.keypair,transaction:i,options:{showEffects:!0,showObjectChanges:!0}});if(a&&a.length>0)throw new Error(`Transaction failed with errors: ${a.map(s=>s.toString()).join(", ")}`);return !0}catch(i){throw new Error(`Failed to supply to margin pool: ${i.message||i}`)}}async withdrawFromMarginPool(r,e){try{if(!this.supplierCapId)throw new Error("Supplier Cap not initialized. Call initialize() first.");let t=new transactions.Transaction,i=t.object(this.supplierCapId),a=this.marginPoolContract.withdrawFromMarginPool(r,i,e)(t);t.transferObjects([a],this.address);let{errors:s}=await this.suiClient.signAndExecuteTransaction({signer:this.keypair,transaction:t,options:{showEffects:!0,showObjectChanges:!0}});if(s&&s.length>0)throw new Error(`Transaction failed with errors: ${s.map(p=>p.toString()).join(", ")}`);return !0}catch(t){throw new Error(`Failed to withdraw from margin pool: ${t.message||t}`)}}async withdrawReferralFees(r,e){try{let t=new transactions.Transaction;t.add(this.marginPoolContract.withdrawReferralFees(r,e));let{errors:i}=await this.suiClient.signAndExecuteTransaction({signer:this.keypair,transaction:t,options:{showEffects:!0,showObjectChanges:!0,showBalanceChanges:!0}});if(i&&i.length>0)throw new Error(`Transaction failed with errors: ${i.map(o=>o.toString()).join(", ")}`);return !0}catch(t){throw new Error(`Failed to withdraw referral fees: ${t.message||t}`)}}async getBalance(r){try{if(!this.supplierCapId)throw new Error("Supplier Cap not initialized. Call initialize() first.");let e=new transactions.Transaction;e.add(this.marginPoolContract.userSupplyAmount(r,this.supplierCapId));let t=await this.suiClient.devInspectTransactionBlock({sender:this.address,transactionBlock:e}),i=0;if(t&&t.results&&t.results[0]&&t.results[0].returnValues){let l=t.results[0].returnValues[0];if(l&&l[0]){let c=Buffer.from(l[0]).readBigUInt64LE(),m=this.dbConfig.getCoin(r).scalar;i=Number(c)/m;}}let o=this.dbConfig.getCoin(r).type,a=await this.suiClient.getBalance({owner:this.address,coinType:o}),s=this.dbConfig.getCoin(r).scalar,p=Number(a.totalBalance)/s;return {userSupplyAmount:i,walletBalance:p}}catch(e){throw new Error(`Failed to get balance: ${e.message||e}`)}}getSupplierCapId(){return this.supplierCapId}getAddress(){return this.address}};var w=["supplyCap","maxUtilizationRate","protocolSpread","minBorrow","interestRate","totalSupply","supplyShares","totalBorrow","borrowShares","lastUpdateTimestamp"],h=["userSupplyShares","userSupplyAmount"],_={supplyCap:"U64",maxUtilizationRate:"U64",protocolSpread:"U64",minBorrow:"U64",interestRate:"U64",totalSupply:"U64",supplyShares:"U64",totalBorrow:"U64",borrowShares:"U64",lastUpdateTimestamp:"U64",userSupplyShares:"U64",userSupplyAmount:"U64"};var d=(n,r)=>n*r/BigInt(deepbookV3.FLOAT_SCALAR),g=n=>Number(n)/deepbookV3.FLOAT_SCALAR;var W=new Set(h),D=n=>W.has(n),b=class{marginPoolContract;dbConfig;suiClient;constructor({env:r="mainnet",address:e="",suiClient:t=new client.SuiClient({url:client.getFullnodeUrl(r)}),dbConfig:i=new deepbookV3.DeepBookConfig({env:r,address:e})}={}){if(this.dbConfig=i,this.suiClient=t,this.marginPoolContract=new deepbookV3.MarginPoolContract(this.dbConfig),r!==this.env)throw new Error(`Mismatch between provided env (${r}) and dbConfig env (${this.env}).`)}get env(){return this.dbConfig.env}#r(r,e,t,i){if(D(e)){let o=this.marginPoolContract[e];if(i==null)throw new Error(`supplierCap is required for '${e}'.`);r.add(o(t,i));}else {let o=this.marginPoolContract[e];r.add(o(t));}}parseInspectResultToBcsStructs(r,e){let t=r.results;if(!t)throw new Error("No results found in DevInspect output.");return e.reduce((i,o,a)=>{let s=t[a]?.returnValues?.[0]?.[0];if(!s)return i;let p=bcs.bcs[_[o]];return i[o]=p.parse(new Uint8Array(s)),i},{})}formatResult(r,e){let t=this.dbConfig.getCoin(e),i={supplyCap:0,maxUtilizationRate:0,protocolSpread:0,minBorrow:0,interestRate:0,totalSupply:0,supplyShares:0,totalBorrow:0,borrowShares:0,lastUpdateTimestamp:0,userSupplyShares:0,userSupplyAmount:0,decimals:t.scalar.toString().length-1,highKink:0,baseBorrowApr:0,borrowAprOnHighKink:0,maxBorrowApr:0,supplyApr:0,utilizationRate:0,...t};if(!t)return i;let o=new Set(["interestRate","maxUtilizationRate","protocolSpread"]);for(let[a,s]of Object.entries(r))a==="lastUpdateTimestamp"?i[a]=Number(s):o.has(a)?i[a]=new bignumber_js.BigNumber(s).dividedBy(deepbookV3.FLOAT_SCALAR).toNumber():i[a]=new bignumber_js.BigNumber(s).dividedBy(t.scalar).toNumber();return i}computeBorrowAprAtUtil(r,e){let t=BigInt(e.base_rate),i=BigInt(e.base_slope),o=BigInt(e.excess_slope),a=BigInt(e.optimal_utilization);return r<a?t+d(r,i):t+d(a,i)+d(r-a,o)}calculateKinksAndRate(r,e,t,i){let o=BigInt(r.optimal_utilization),a=BigInt(e.max_utilization_rate),s=this.computeBorrowAprAtUtil(o,r),p=this.computeBorrowAprAtUtil(a,r),l=BigInt(bignumber_js.BigNumber(t.total_borrow).dividedBy(t.total_supply).shiftedBy(9).decimalPlaces(0).toString()),c=d(d(i,l),BigInt(deepbookV3.FLOAT_SCALAR)-BigInt(e.protocol_spread));return {raw:{baseBorrowApr:r.base_rate,highKink:o,borrowAprOnHighKink:s,maxBorrowApr:p,supplyApr:c,utilizationRate:l},normalized:{baseBorrowApr:g(BigInt(r.base_rate)),highKink:g(o),borrowAprOnHighKink:g(s),maxBorrowApr:g(p),supplyApr:g(c),utilizationRate:g(l)}}}async#t(r,e){let{address:t}=this.dbConfig.getMarginPool(r),o=((await this.suiClient.getObject({id:t,options:{showContent:true}})).data?.content).fields,a=o.config.fields,s=a.interest_config.fields,p=a.margin_pool_config.fields,l=o.state.fields,{normalized:c}=this.calculateKinksAndRate(s,p,l,e);return c}async getPoolParameters(r,e,t=new transactions.Transaction,i=true){if(w.forEach(m=>this.#r(t,m,r)),e&&h.forEach(m=>this.#r(t,m,r,e)),!i)return t;let o=[...w,...h],a=await this.suiClient.devInspectTransactionBlock({transactionBlock:t,sender:this.dbConfig.address}),s=this.parseInspectResultToBcsStructs(a,o),p=this.formatResult(s,r),l=BigInt(s.interestRate??0),c=await this.#t(r,l);return {...p,...c}}};exports.DeepBookMarginPool=b;exports.DeepBookMarginToolkit=P;
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import {getFullnodeUrl,SuiClient}from'@mysten/sui/client';import {Ed25519Keypair}from'@mysten/sui/keypairs/ed25519';import {Transaction}from'@mysten/sui/transactions';import {DeepBookConfig,MarginPoolContract,FLOAT_SCALAR}from'@mysten/deepbook-v3';import {SUI_PRIVATE_KEY_PREFIX,decodeSuiPrivateKey,LEGACY_PRIVATE_KEY_SIZE,PRIVATE_KEY_SIZE}from'@mysten/sui/cryptography';import {fromHex,fromBase64}from'@mysten/bcs';import {bcs}from'@mysten/sui/bcs';import {BigNumber}from'bignumber.js';var K=a=>/^0x[0-9a-fA-F]+$|^[0-9a-fA-F]+$/.test(a),B=a=>/^[a-zA-Z0-9+/]+={0,2}$/g.test(a),S=a=>{if(K(a))return fromHex(a);if(B(a))return fromBase64(a);throw new Error("The string is not a valid hex or base64 string.")},f=a=>{if(a.length===LEGACY_PRIVATE_KEY_SIZE)return a.slice(0,PRIVATE_KEY_SIZE);if(a.length===PRIVATE_KEY_SIZE+1&&a[0]===0)return a.slice(1);if(a.length===PRIVATE_KEY_SIZE)return a;throw new Error("invalid secret key")};var C=class{suiClient;keypair;address;marginPoolContract;supplierCapId;dbConfig;supplierCapPackageId;constructor({network:r,fullnodeUrl:e,supplierCapId:t,privateKey:i,supplierCapPackageId:o,dbConfig:n}){let s=e??getFullnodeUrl(r);this.suiClient=new SuiClient({url:s}),this.keypair=this.#r(i),this.address=this.keypair.getPublicKey().toSuiAddress(),this.supplierCapId=t,this.dbConfig=n??new DeepBookConfig({env:r,address:this.address}),this.marginPoolContract=new MarginPoolContract(this.dbConfig),this.supplierCapPackageId=o??this.dbConfig.MARGIN_PACKAGE_ID;}#r(r){if(r.startsWith(SUI_PRIVATE_KEY_PREFIX)){let{secretKey:e}=decodeSuiPrivateKey(r);return Ed25519Keypair.fromSecretKey(f(e))}return Ed25519Keypair.fromSecretKey(f(S(r)))}async#t(){let r=`${this.dbConfig.MARGIN_PACKAGE_ID}::margin_pool::SupplierCap`;return (await this.suiClient.getOwnedObjects({owner:this.address,filter:{StructType:r},options:{showType:true}})).data?.[0]?.data?.objectId}async initialize(){if(this.supplierCapId)return this.supplierCapId;let r=await this.#t();if(r)return this.supplierCapId=r,r;let e=await this.createSupplierCap();if(!e)throw new Error("Failed to create Supplier Cap");return this.supplierCapId=e,e}async createSupplierCap(){try{let r=new Transaction;r.setSender(this.address);let e=r.moveCall({target:`${this.supplierCapPackageId}::margin_pool::mint_supplier_cap`,arguments:[r.object(this.dbConfig.MARGIN_REGISTRY_ID),r.object.clock()]});r.transferObjects([e],r.pure.address(this.address));let t=await this.suiClient.signAndExecuteTransaction({signer:this.keypair,transaction:r,options:{showEffects:!0,showObjectChanges:!0}});if(t.errors&&t.errors.length>0)throw new Error(`Transaction failed with errors: ${t.errors.map(i=>i.toString()).join(", ")}`);if(t.objectChanges){for(let i of t.objectChanges)if(i.type==="created"&&i.objectType.includes("SupplierCap"))return i.objectId}return null}catch(r){throw new Error(`Failed to create Supplier Cap: ${r.message||r}`)}}async createSupplyReferral(r){try{let e=new Transaction;e.setSender(this.address);let t=this.dbConfig.getMarginPool(r);if(!t)throw new Error(`Margin pool configuration not found for coin: ${r}`);e.moveCall({target:`${this.dbConfig.MARGIN_PACKAGE_ID}::margin_pool::mint_supply_referral`,arguments:[e.object(t.address),e.object(this.dbConfig.MARGIN_REGISTRY_ID),e.object.clock()],typeArguments:[t.type]});let i=await this.suiClient.signAndExecuteTransaction({signer:this.keypair,transaction:e,options:{showEffects:!0,showObjectChanges:!0}});if(i.errors&&i.errors.length>0)throw new Error(`Transaction failed with errors: ${i.errors.map(o=>o.toString()).join(", ")}`);if(i.objectChanges){for(let o of i.objectChanges)if(o.type==="created"&&o.objectType.includes("SupplyReferral"))return o.objectId}return null}catch(e){throw new Error(`Failed to create Supply Referral: ${e.message||e}`)}}async supplyToMarginPool(r,e,t){try{if(!this.supplierCapId)throw new Error("Supplier Cap not initialized. Call initialize() first.");let i=new Transaction;i.setSender(this.address);let o=i.object(this.supplierCapId);i.add(this.marginPoolContract.supplyToMarginPool(r,o,e,t));let{errors:n}=await this.suiClient.signAndExecuteTransaction({signer:this.keypair,transaction:i,options:{showEffects:!0,showObjectChanges:!0}});if(n&&n.length>0)throw new Error(`Transaction failed with errors: ${n.map(s=>s.toString()).join(", ")}`);return !0}catch(i){throw new Error(`Failed to supply to margin pool: ${i.message||i}`)}}async withdrawFromMarginPool(r,e){try{if(!this.supplierCapId)throw new Error("Supplier Cap not initialized. Call initialize() first.");let t=new Transaction,i=t.object(this.supplierCapId),n=this.marginPoolContract.withdrawFromMarginPool(r,i,e)(t);t.transferObjects([n],this.address);let{errors:s}=await this.suiClient.signAndExecuteTransaction({signer:this.keypair,transaction:t,options:{showEffects:!0,showObjectChanges:!0}});if(s&&s.length>0)throw new Error(`Transaction failed with errors: ${s.map(l=>l.toString()).join(", ")}`);return !0}catch(t){throw new Error(`Failed to withdraw from margin pool: ${t.message||t}`)}}async withdrawReferralFees(r,e){try{let t=new Transaction;t.add(this.marginPoolContract.withdrawReferralFees(r,e));let{errors:i}=await this.suiClient.signAndExecuteTransaction({signer:this.keypair,transaction:t,options:{showEffects:!0,showObjectChanges:!0,showBalanceChanges:!0}});if(i&&i.length>0)throw new Error(`Transaction failed with errors: ${i.map(o=>o.toString()).join(", ")}`);return !0}catch(t){throw new Error(`Failed to withdraw referral fees: ${t.message||t}`)}}async getBalance(r){try{if(!this.supplierCapId)throw new Error("Supplier Cap not initialized. Call initialize() first.");let e=new Transaction;e.add(this.marginPoolContract.userSupplyAmount(r,this.supplierCapId));let t=await this.suiClient.devInspectTransactionBlock({sender:this.address,transactionBlock:e}),i=0;if(t&&t.results&&t.results[0]&&t.results[0].returnValues){let p=t.results[0].returnValues[0];if(p&&p[0]){let g=Buffer.from(p[0]).readBigUInt64LE(),R=this.dbConfig.getCoin(r).scalar;i=Number(g)/R;}}let o=this.dbConfig.getCoin(r).type,n=await this.suiClient.getBalance({owner:this.address,coinType:o}),s=this.dbConfig.getCoin(r).scalar,l=Number(n.totalBalance)/s;return {userSupplyAmount:i,walletBalance:l}}catch(e){throw new Error(`Failed to get balance: ${e.message||e}`)}}getSupplierCapId(){return this.supplierCapId}getAddress(){return this.address}};var P=["supplyCap","maxUtilizationRate","protocolSpread","minBorrow","interestRate","totalSupply","supplyShares","totalBorrow","borrowShares","lastUpdateTimestamp"],m=["userSupplyShares","userSupplyAmount"],A={supplyCap:"U64",maxUtilizationRate:"U64",protocolSpread:"U64",minBorrow:"U64",interestRate:"U64",totalSupply:"U64",supplyShares:"U64",totalBorrow:"U64",borrowShares:"U64",lastUpdateTimestamp:"U64",userSupplyShares:"U64",userSupplyAmount:"U64"};var d=(a,r)=>a*r/BigInt(FLOAT_SCALAR),c=a=>Number(a)/FLOAT_SCALAR;var W=new Set(m),Y=a=>W.has(a),b=class{marginPoolContract;dbConfig;suiClient;constructor({env:r="mainnet",address:e="",suiClient:t=new SuiClient({url:getFullnodeUrl(r)}),dbConfig:i=new DeepBookConfig({env:r,address:e})}={}){if(this.dbConfig=i,this.suiClient=t,this.marginPoolContract=new MarginPoolContract(this.dbConfig),r!==this.env)throw new Error(`Mismatch between provided env (${r}) and dbConfig env (${this.env}).`)}get env(){return this.dbConfig.env}#r(r,e,t,i){if(Y(e)){let o=this.marginPoolContract[e];if(i==null)throw new Error(`supplierCap is required for '${e}'.`);r.add(o(t,i));}else {let o=this.marginPoolContract[e];r.add(o(t));}}#t(r,e){let t=r.results;return t?e.reduce((i,o,n)=>{let s=t[n]?.returnValues?.[0]?.[0];if(!s)return i;let l=bcs[A[o]];return i[o]=l.parse(new Uint8Array(s)),i},{}):{}}#i(r,e){let t=this.dbConfig.getCoin(e),i={supplyCap:0,maxUtilizationRate:0,protocolSpread:0,minBorrow:0,interestRate:0,totalSupply:0,supplyShares:0,totalBorrow:0,borrowShares:0,lastUpdateTimestamp:0,userSupplyShares:0,userSupplyAmount:0,decimals:this.dbConfig.getCoin(e).scalar.toString().length-1,highKink:0,baseBorrowApr:0,borrowAprOnHighKink:0,maxBorrowApr:0,supplyApr:0,utilizationRate:0,feed:"",currencyId:"",priceInfoObjectId:"",...t};if(!t)return i;let o=new Set(["interestRate","maxUtilizationRate","protocolSpread"]);for(let[n,s]of Object.entries(r))n==="lastUpdateTimestamp"?i[n]=Number(s):o.has(n)?i[n]=new BigNumber(s).dividedBy(FLOAT_SCALAR).toNumber():i[n]=new BigNumber(s).dividedBy(t.scalar).toNumber();return i}#e(r,e){let t=BigInt(e.base_rate),i=BigInt(e.base_slope),o=BigInt(e.excess_slope),n=BigInt(e.optimal_utilization);return r<n?t+d(r,i):t+d(n,i)+d(r-n,o)}#o(r,e,t,i){let o=BigInt(r.optimal_utilization),n=BigInt(e.max_utilization_rate),s=this.#e(o,r),l=this.#e(n,r),p=BigInt(BigNumber(t.total_borrow).dividedBy(t.total_supply).shiftedBy(9).decimalPlaces(0).toString()),g=d(d(BigInt(i),p),BigInt(FLOAT_SCALAR)-BigInt(e.protocol_spread));return {raw:{baseBorrowApr:r.base_rate,highKink:o,borrowAprOnHighKink:s,maxBorrowApr:l,supplyApr:g,utilizationRate:p},normalized:{baseBorrowApr:c(BigInt(r.base_rate)),highKink:c(o),borrowAprOnHighKink:c(s),maxBorrowApr:c(l),supplyApr:c(g),utilizationRate:c(p)}}}async#n(r,e){let{address:t}=this.dbConfig.getMarginPool(r),o=((await this.suiClient.getObject({id:t,options:{showContent:true}})).data?.content).fields,n=o.config.fields,s=n.interest_config.fields,l=n.margin_pool_config.fields,p=o.state.fields,{normalized:g}=this.#o(s,l,p,e);return g}async getPoolParameters(r,e,t=new Transaction,i=true){if(P.forEach(p=>this.#r(t,p,r)),e&&m.forEach(p=>this.#r(t,p,r,e)),!i)return t;let o=[...P,...m],n=await this.suiClient.devInspectTransactionBlock({transactionBlock:t,sender:this.dbConfig.address}),s=this.#i(this.#t(n,o),r),l=await this.#n(r,s.interestRate*FLOAT_SCALAR);return {...s,...l}}};export{b as DeepBookMarginPool,C as DeepBookMarginToolkit};
1
+ import {getFullnodeUrl,SuiClient}from'@mysten/sui/client';import {Ed25519Keypair}from'@mysten/sui/keypairs/ed25519';import {Transaction}from'@mysten/sui/transactions';import {DeepBookConfig,MarginPoolContract,FLOAT_SCALAR}from'@mysten/deepbook-v3';import {SUI_PRIVATE_KEY_PREFIX,decodeSuiPrivateKey,LEGACY_PRIVATE_KEY_SIZE,PRIVATE_KEY_SIZE}from'@mysten/sui/cryptography';import {fromHex,fromBase64}from'@mysten/bcs';import {bcs}from'@mysten/sui/bcs';import {BigNumber}from'bignumber.js';var T=n=>/^0x[0-9a-fA-F]+$|^[0-9a-fA-F]+$/.test(n),B=n=>/^[a-zA-Z0-9+/]+={0,2}$/g.test(n),A=n=>{if(T(n))return fromHex(n);if(B(n))return fromBase64(n);throw new Error("The string is not a valid hex or base64 string.")},C=n=>{if(n.length===LEGACY_PRIVATE_KEY_SIZE)return n.slice(0,PRIVATE_KEY_SIZE);if(n.length===PRIVATE_KEY_SIZE+1&&n[0]===0)return n.slice(1);if(n.length===PRIVATE_KEY_SIZE)return n;throw new Error("invalid secret key")};var P=class{suiClient;keypair;address;marginPoolContract;supplierCapId;dbConfig;supplierCapPackageId;constructor({network:r,fullnodeUrl:e,supplierCapId:t,privateKey:i,supplierCapPackageId:o,dbConfig:a}){let s=e??getFullnodeUrl(r);this.suiClient=new SuiClient({url:s}),this.keypair=this.#r(i),this.address=this.keypair.getPublicKey().toSuiAddress(),this.supplierCapId=t,this.dbConfig=a??new DeepBookConfig({env:r,address:this.address}),this.marginPoolContract=new MarginPoolContract(this.dbConfig),this.supplierCapPackageId=o??this.dbConfig.MARGIN_PACKAGE_ID;}#r(r){if(r.startsWith(SUI_PRIVATE_KEY_PREFIX)){let{secretKey:e}=decodeSuiPrivateKey(r);return Ed25519Keypair.fromSecretKey(C(e))}return Ed25519Keypair.fromSecretKey(C(A(r)))}async#t(){let r=`${this.dbConfig.MARGIN_PACKAGE_ID}::margin_pool::SupplierCap`;return (await this.suiClient.getOwnedObjects({owner:this.address,filter:{StructType:r},options:{showType:true}})).data?.[0]?.data?.objectId}async initialize(){if(this.supplierCapId)return this.supplierCapId;let r=await this.#t();if(r)return this.supplierCapId=r,r;let e=await this.createSupplierCap();if(!e)throw new Error("Failed to create Supplier Cap");return this.supplierCapId=e,e}async createSupplierCap(){try{let r=new Transaction;r.setSender(this.address);let e=r.moveCall({target:`${this.supplierCapPackageId}::margin_pool::mint_supplier_cap`,arguments:[r.object(this.dbConfig.MARGIN_REGISTRY_ID),r.object.clock()]});r.transferObjects([e],r.pure.address(this.address));let t=await this.suiClient.signAndExecuteTransaction({signer:this.keypair,transaction:r,options:{showEffects:!0,showObjectChanges:!0}});if(t.errors&&t.errors.length>0)throw new Error(`Transaction failed with errors: ${t.errors.map(i=>i.toString()).join(", ")}`);if(t.objectChanges){for(let i of t.objectChanges)if(i.type==="created"&&i.objectType.includes("SupplierCap"))return i.objectId}return null}catch(r){throw new Error(`Failed to create Supplier Cap: ${r.message||r}`)}}async createSupplyReferral(r){try{let e=new Transaction;e.setSender(this.address);let t=this.dbConfig.getMarginPool(r);if(!t)throw new Error(`Margin pool configuration not found for coin: ${r}`);e.moveCall({target:`${this.dbConfig.MARGIN_PACKAGE_ID}::margin_pool::mint_supply_referral`,arguments:[e.object(t.address),e.object(this.dbConfig.MARGIN_REGISTRY_ID),e.object.clock()],typeArguments:[t.type]});let i=await this.suiClient.signAndExecuteTransaction({signer:this.keypair,transaction:e,options:{showEffects:!0,showObjectChanges:!0}});if(i.errors&&i.errors.length>0)throw new Error(`Transaction failed with errors: ${i.errors.map(o=>o.toString()).join(", ")}`);if(i.objectChanges){for(let o of i.objectChanges)if(o.type==="created"&&o.objectType.includes("SupplyReferral"))return o.objectId}return null}catch(e){throw new Error(`Failed to create Supply Referral: ${e.message||e}`)}}async supplyToMarginPool(r,e,t){try{if(!this.supplierCapId)throw new Error("Supplier Cap not initialized. Call initialize() first.");let i=new Transaction;i.setSender(this.address);let o=i.object(this.supplierCapId);i.add(this.marginPoolContract.supplyToMarginPool(r,o,e,t));let{errors:a}=await this.suiClient.signAndExecuteTransaction({signer:this.keypair,transaction:i,options:{showEffects:!0,showObjectChanges:!0}});if(a&&a.length>0)throw new Error(`Transaction failed with errors: ${a.map(s=>s.toString()).join(", ")}`);return !0}catch(i){throw new Error(`Failed to supply to margin pool: ${i.message||i}`)}}async withdrawFromMarginPool(r,e){try{if(!this.supplierCapId)throw new Error("Supplier Cap not initialized. Call initialize() first.");let t=new Transaction,i=t.object(this.supplierCapId),a=this.marginPoolContract.withdrawFromMarginPool(r,i,e)(t);t.transferObjects([a],this.address);let{errors:s}=await this.suiClient.signAndExecuteTransaction({signer:this.keypair,transaction:t,options:{showEffects:!0,showObjectChanges:!0}});if(s&&s.length>0)throw new Error(`Transaction failed with errors: ${s.map(p=>p.toString()).join(", ")}`);return !0}catch(t){throw new Error(`Failed to withdraw from margin pool: ${t.message||t}`)}}async withdrawReferralFees(r,e){try{let t=new Transaction;t.add(this.marginPoolContract.withdrawReferralFees(r,e));let{errors:i}=await this.suiClient.signAndExecuteTransaction({signer:this.keypair,transaction:t,options:{showEffects:!0,showObjectChanges:!0,showBalanceChanges:!0}});if(i&&i.length>0)throw new Error(`Transaction failed with errors: ${i.map(o=>o.toString()).join(", ")}`);return !0}catch(t){throw new Error(`Failed to withdraw referral fees: ${t.message||t}`)}}async getBalance(r){try{if(!this.supplierCapId)throw new Error("Supplier Cap not initialized. Call initialize() first.");let e=new Transaction;e.add(this.marginPoolContract.userSupplyAmount(r,this.supplierCapId));let t=await this.suiClient.devInspectTransactionBlock({sender:this.address,transactionBlock:e}),i=0;if(t&&t.results&&t.results[0]&&t.results[0].returnValues){let l=t.results[0].returnValues[0];if(l&&l[0]){let c=Buffer.from(l[0]).readBigUInt64LE(),m=this.dbConfig.getCoin(r).scalar;i=Number(c)/m;}}let o=this.dbConfig.getCoin(r).type,a=await this.suiClient.getBalance({owner:this.address,coinType:o}),s=this.dbConfig.getCoin(r).scalar,p=Number(a.totalBalance)/s;return {userSupplyAmount:i,walletBalance:p}}catch(e){throw new Error(`Failed to get balance: ${e.message||e}`)}}getSupplierCapId(){return this.supplierCapId}getAddress(){return this.address}};var w=["supplyCap","maxUtilizationRate","protocolSpread","minBorrow","interestRate","totalSupply","supplyShares","totalBorrow","borrowShares","lastUpdateTimestamp"],h=["userSupplyShares","userSupplyAmount"],_={supplyCap:"U64",maxUtilizationRate:"U64",protocolSpread:"U64",minBorrow:"U64",interestRate:"U64",totalSupply:"U64",supplyShares:"U64",totalBorrow:"U64",borrowShares:"U64",lastUpdateTimestamp:"U64",userSupplyShares:"U64",userSupplyAmount:"U64"};var d=(n,r)=>n*r/BigInt(FLOAT_SCALAR),g=n=>Number(n)/FLOAT_SCALAR;var W=new Set(h),D=n=>W.has(n),b=class{marginPoolContract;dbConfig;suiClient;constructor({env:r="mainnet",address:e="",suiClient:t=new SuiClient({url:getFullnodeUrl(r)}),dbConfig:i=new DeepBookConfig({env:r,address:e})}={}){if(this.dbConfig=i,this.suiClient=t,this.marginPoolContract=new MarginPoolContract(this.dbConfig),r!==this.env)throw new Error(`Mismatch between provided env (${r}) and dbConfig env (${this.env}).`)}get env(){return this.dbConfig.env}#r(r,e,t,i){if(D(e)){let o=this.marginPoolContract[e];if(i==null)throw new Error(`supplierCap is required for '${e}'.`);r.add(o(t,i));}else {let o=this.marginPoolContract[e];r.add(o(t));}}parseInspectResultToBcsStructs(r,e){let t=r.results;if(!t)throw new Error("No results found in DevInspect output.");return e.reduce((i,o,a)=>{let s=t[a]?.returnValues?.[0]?.[0];if(!s)return i;let p=bcs[_[o]];return i[o]=p.parse(new Uint8Array(s)),i},{})}formatResult(r,e){let t=this.dbConfig.getCoin(e),i={supplyCap:0,maxUtilizationRate:0,protocolSpread:0,minBorrow:0,interestRate:0,totalSupply:0,supplyShares:0,totalBorrow:0,borrowShares:0,lastUpdateTimestamp:0,userSupplyShares:0,userSupplyAmount:0,decimals:t.scalar.toString().length-1,highKink:0,baseBorrowApr:0,borrowAprOnHighKink:0,maxBorrowApr:0,supplyApr:0,utilizationRate:0,...t};if(!t)return i;let o=new Set(["interestRate","maxUtilizationRate","protocolSpread"]);for(let[a,s]of Object.entries(r))a==="lastUpdateTimestamp"?i[a]=Number(s):o.has(a)?i[a]=new BigNumber(s).dividedBy(FLOAT_SCALAR).toNumber():i[a]=new BigNumber(s).dividedBy(t.scalar).toNumber();return i}computeBorrowAprAtUtil(r,e){let t=BigInt(e.base_rate),i=BigInt(e.base_slope),o=BigInt(e.excess_slope),a=BigInt(e.optimal_utilization);return r<a?t+d(r,i):t+d(a,i)+d(r-a,o)}calculateKinksAndRate(r,e,t,i){let o=BigInt(r.optimal_utilization),a=BigInt(e.max_utilization_rate),s=this.computeBorrowAprAtUtil(o,r),p=this.computeBorrowAprAtUtil(a,r),l=BigInt(BigNumber(t.total_borrow).dividedBy(t.total_supply).shiftedBy(9).decimalPlaces(0).toString()),c=d(d(i,l),BigInt(FLOAT_SCALAR)-BigInt(e.protocol_spread));return {raw:{baseBorrowApr:r.base_rate,highKink:o,borrowAprOnHighKink:s,maxBorrowApr:p,supplyApr:c,utilizationRate:l},normalized:{baseBorrowApr:g(BigInt(r.base_rate)),highKink:g(o),borrowAprOnHighKink:g(s),maxBorrowApr:g(p),supplyApr:g(c),utilizationRate:g(l)}}}async#t(r,e){let{address:t}=this.dbConfig.getMarginPool(r),o=((await this.suiClient.getObject({id:t,options:{showContent:true}})).data?.content).fields,a=o.config.fields,s=a.interest_config.fields,p=a.margin_pool_config.fields,l=o.state.fields,{normalized:c}=this.calculateKinksAndRate(s,p,l,e);return c}async getPoolParameters(r,e,t=new Transaction,i=true){if(w.forEach(m=>this.#r(t,m,r)),e&&h.forEach(m=>this.#r(t,m,r,e)),!i)return t;let o=[...w,...h],a=await this.suiClient.devInspectTransactionBlock({transactionBlock:t,sender:this.dbConfig.address}),s=this.parseInspectResultToBcsStructs(a,o),p=this.formatResult(s,r),l=BigInt(s.interestRate??0),c=await this.#t(r,l);return {...p,...c}}};export{b as DeepBookMarginPool,P as DeepBookMarginToolkit};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scallop-io/scallop-deepbook-kit",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "A toolkit for integrating Scallop with DeepBook functionality",
5
5
  "keywords": [
6
6
  "scallop",
@@ -31,8 +31,9 @@ const main = async () => {
31
31
  marginPools: MARGIN_POOLS,
32
32
  }),
33
33
  });
34
- const suiMarginPoolParams = await dbMarginPool.getPoolParameters('SUI');
35
- console.log('SUI Margin Pool Parameters:', suiMarginPoolParams);
34
+ const coinKey = 'USDC';
35
+ const suiMarginPoolParams = await dbMarginPool.getPoolParameters(coinKey);
36
+ console.log(`${coinKey} Margin Pool Parameters:`, suiMarginPoolParams);
36
37
  } catch (error) {
37
38
  console.error('An error occurred:', error);
38
39
  } finally {
@@ -1,4 +1,4 @@
1
- import { DeepBookConfig, FLOAT_SCALAR, MarginPoolContract } from '@mysten/deepbook-v3';
1
+ import { Coin, DeepBookConfig, FLOAT_SCALAR, MarginPoolContract } from '@mysten/deepbook-v3';
2
2
  import { bcs } from '@mysten/sui/bcs';
3
3
  import { DevInspectResults, getFullnodeUrl, SuiClient } from '@mysten/sui/client';
4
4
  import { Transaction } from '@mysten/sui/transactions';
@@ -25,15 +25,8 @@ export type MarginPoolParams = Record<
25
25
  MarginPoolParamKey | MarginPoolWithSupplierCapParamKey,
26
26
  number
27
27
  > &
28
- InterestConfig & {
29
- address: string;
30
- type: string;
31
- scalar: number;
32
- decimals: number;
33
- feed: string;
34
- currencyId: string;
35
- priceInfoObjectId: string;
36
- };
28
+ InterestConfig &
29
+ Coin & { decimals: number };
37
30
 
38
31
  type RawInterestConfig = {
39
32
  base_rate: string;
@@ -169,12 +162,12 @@ export class DeepBookMarginPool {
169
162
  * Parse DevInspect results into BCS-decoded parameter objects.
170
163
  * Used to extract actual values returned from contract functions.
171
164
  */
172
- #parseInspectResultToBcsStructs(
165
+ private parseInspectResultToBcsStructs(
173
166
  inspectResults: DevInspectResults,
174
167
  keys: (MarginPoolParamKey | MarginPoolWithSupplierCapParamKey)[]
175
- ) {
168
+ ): Record<MarginPoolParamKey | MarginPoolWithSupplierCapParamKey, string> {
176
169
  const results = inspectResults.results;
177
- if (!results) return {};
170
+ if (!results) throw new Error('No results found in DevInspect output.');
178
171
 
179
172
  return keys.reduce(
180
173
  (acc, key, idx) => {
@@ -188,11 +181,11 @@ export class DeepBookMarginPool {
188
181
 
189
182
  return acc;
190
183
  },
191
- {} as Record<string, string>
184
+ {} as Record<MarginPoolParamKey | MarginPoolWithSupplierCapParamKey, string>
192
185
  );
193
186
  }
194
187
 
195
- #formatResult(
188
+ private formatResult(
196
189
  result: Record<MarginPoolParamKey | MarginPoolWithSupplierCapParamKey, string>,
197
190
  coinKey: string
198
191
  ): MarginPoolParams {
@@ -211,16 +204,13 @@ export class DeepBookMarginPool {
211
204
  lastUpdateTimestamp: 0,
212
205
  userSupplyShares: 0,
213
206
  userSupplyAmount: 0,
214
- decimals: this.dbConfig.getCoin(coinKey).scalar.toString().length - 1,
207
+ decimals: coin.scalar.toString().length - 1,
215
208
  highKink: 0,
216
209
  baseBorrowApr: 0,
217
210
  borrowAprOnHighKink: 0,
218
211
  maxBorrowApr: 0,
219
212
  supplyApr: 0,
220
213
  utilizationRate: 0,
221
- feed: '',
222
- currencyId: '',
223
- priceInfoObjectId: '',
224
214
  ...coin,
225
215
  };
226
216
 
@@ -257,7 +247,7 @@ export class DeepBookMarginPool {
257
247
  * r(U) = base_rate + mul(optimal, base_slope) + mul(U - optimal, excess_slope)
258
248
  * }
259
249
  */
260
- #computeBorrowAprAtUtil(
250
+ private computeBorrowAprAtUtil(
261
251
  util: bigint, // 1e9-scaled utilization
262
252
  cfg: RawInterestConfig
263
253
  ): bigint {
@@ -273,18 +263,17 @@ export class DeepBookMarginPool {
273
263
  return baseRate + mul(optimalUtil, baseSlope) + mul(util - optimalUtil, excessSlope);
274
264
  }
275
265
 
276
- #calculateKinksAndRate(
266
+ private calculateKinksAndRate(
277
267
  interestConfig: RawInterestConfig,
278
268
  marginPoolConfig: RawMarginPoolConfig,
279
269
  state: RawStatePoolConfig,
280
- borrowApr: number
270
+ borrowAprScaled: bigint
281
271
  ) {
282
272
  const highKink = BigInt(interestConfig.optimal_utilization); // v0
283
273
  const maxKink = BigInt(marginPoolConfig.max_utilization_rate); // U_max
284
274
 
285
- // const midBorrowApr = this.#computeBorrowAprAtUtil(midKink, interestConfig);
286
- const borrowAprOnHighKink = this.#computeBorrowAprAtUtil(highKink, interestConfig);
287
- const maxBorrowApr = this.#computeBorrowAprAtUtil(maxKink, interestConfig);
275
+ const borrowAprOnHighKink = this.computeBorrowAprAtUtil(highKink, interestConfig);
276
+ const maxBorrowApr = this.computeBorrowAprAtUtil(maxKink, interestConfig);
288
277
 
289
278
  const utilizationRate = BigInt(
290
279
  BigNumber(state.total_borrow)
@@ -293,27 +282,24 @@ export class DeepBookMarginPool {
293
282
  .decimalPlaces(0)
294
283
  .toString()
295
284
  );
285
+
296
286
  const supplyApr = mul(
297
- mul(BigInt(borrowApr), utilizationRate),
287
+ mul(borrowAprScaled, utilizationRate),
298
288
  BigInt(FLOAT_SCALAR) - BigInt(marginPoolConfig.protocol_spread)
299
289
  );
300
290
 
301
291
  return {
302
- // raw 1e9-scaled values
303
292
  raw: {
304
293
  baseBorrowApr: interestConfig.base_rate,
305
- highKink, // utilization at kink2
306
- borrowAprOnHighKink, // APR at highKink
307
- maxBorrowApr, // APR at U = 1.0
294
+ highKink,
295
+ borrowAprOnHighKink,
296
+ maxBorrowApr,
308
297
  supplyApr,
309
298
  utilizationRate,
310
299
  },
311
- // convenience normalized numbers
312
300
  normalized: {
313
301
  baseBorrowApr: normalize(BigInt(interestConfig.base_rate)),
314
- // midKink: normalize(midKink),
315
302
  highKink: normalize(highKink),
316
- // midBorrowApr: normalize(midBorrowApr),
317
303
  borrowAprOnHighKink: normalize(borrowAprOnHighKink),
318
304
  maxBorrowApr: normalize(maxBorrowApr),
319
305
  supplyApr: normalize(supplyApr),
@@ -325,9 +311,9 @@ export class DeepBookMarginPool {
325
311
  /**
326
312
  * Internal: Fetch and compute interest configuration parameters.
327
313
  * @param coinKey - Asset key.
328
- * @returns Interest configuration data including kinks and APRs.
314
+ * @param borrowAprScaled - interestRate in FLOAT_SCALAR scale (bigint).
329
315
  */
330
- async #getInterestConfig(coinKey: string, interestRate: number) {
316
+ async #getInterestConfig(coinKey: string, borrowAprScaled: bigint) {
331
317
  const { address } = this.dbConfig.getMarginPool(coinKey);
332
318
  const response = await this.suiClient.getObject({
333
319
  id: address,
@@ -341,12 +327,14 @@ export class DeepBookMarginPool {
341
327
  const interestConfig = config.interest_config.fields as RawInterestConfig;
342
328
  const marginPoolConfig = config.margin_pool_config.fields as RawMarginPoolConfig;
343
329
  const statePoolConfig = fields.state.fields as RawStatePoolConfig;
344
- const { normalized } = this.#calculateKinksAndRate(
330
+
331
+ const { normalized } = this.calculateKinksAndRate(
345
332
  interestConfig,
346
333
  marginPoolConfig,
347
334
  statePoolConfig,
348
- interestRate
335
+ borrowAprScaled
349
336
  );
337
+
350
338
  return normalized;
351
339
  }
352
340
 
@@ -415,14 +403,10 @@ export class DeepBookMarginPool {
415
403
  sender: this.dbConfig.address,
416
404
  });
417
405
 
418
- const formattedResult = this.#formatResult(
419
- this.#parseInspectResultToBcsStructs(inspectResult, allKeys),
420
- coinKey
421
- );
422
- const interestData = await this.#getInterestConfig(
423
- coinKey,
424
- formattedResult.interestRate * FLOAT_SCALAR
425
- );
406
+ const parsed = this.parseInspectResultToBcsStructs(inspectResult, allKeys);
407
+ const formattedResult = this.formatResult(parsed, coinKey);
408
+ const borrowAprScaled = BigInt(parsed.interestRate ?? 0);
409
+ const interestData = await this.#getInterestConfig(coinKey, borrowAprScaled);
426
410
 
427
411
  return {
428
412
  ...formattedResult,