@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 +6 -8
- package/dist/index.d.ts +6 -8
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
- package/src/examples/margin-pool-demo.ts +3 -2
- package/src/toolkit/DeepBookMarginPool.ts +29 -45
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
|
|
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
|
@@ -31,8 +31,9 @@ const main = async () => {
|
|
|
31
31
|
marginPools: MARGIN_POOLS,
|
|
32
32
|
}),
|
|
33
33
|
});
|
|
34
|
-
const
|
|
35
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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)
|
|
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<
|
|
184
|
+
{} as Record<MarginPoolParamKey | MarginPoolWithSupplierCapParamKey, string>
|
|
192
185
|
);
|
|
193
186
|
}
|
|
194
187
|
|
|
195
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
266
|
+
private calculateKinksAndRate(
|
|
277
267
|
interestConfig: RawInterestConfig,
|
|
278
268
|
marginPoolConfig: RawMarginPoolConfig,
|
|
279
269
|
state: RawStatePoolConfig,
|
|
280
|
-
|
|
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
|
-
|
|
286
|
-
const
|
|
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(
|
|
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,
|
|
306
|
-
borrowAprOnHighKink,
|
|
307
|
-
maxBorrowApr,
|
|
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
|
-
* @
|
|
314
|
+
* @param borrowAprScaled - interestRate in FLOAT_SCALAR scale (bigint).
|
|
329
315
|
*/
|
|
330
|
-
async #getInterestConfig(coinKey: string,
|
|
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
|
-
|
|
330
|
+
|
|
331
|
+
const { normalized } = this.calculateKinksAndRate(
|
|
345
332
|
interestConfig,
|
|
346
333
|
marginPoolConfig,
|
|
347
334
|
statePoolConfig,
|
|
348
|
-
|
|
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
|
|
419
|
-
|
|
420
|
-
|
|
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,
|