@defisaver/ethena-sdk 0.0.4 → 0.0.6

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.
Files changed (76) hide show
  1. package/cjs/config/contracts.d.ts +181 -0
  2. package/cjs/config/contracts.js +72 -0
  3. package/cjs/constants/index.d.ts +7 -0
  4. package/cjs/constants/index.js +10 -0
  5. package/cjs/contracts.d.ts +696 -0
  6. package/cjs/contracts.js +80 -0
  7. package/cjs/exchange/index.d.ts +10 -0
  8. package/cjs/exchange/index.js +185 -0
  9. package/cjs/execution/index.d.ts +2 -0
  10. package/cjs/execution/index.js +15 -0
  11. package/cjs/execution/morpho.d.ts +2 -0
  12. package/cjs/execution/morpho.js +56 -0
  13. package/cjs/index.d.ts +5 -1
  14. package/cjs/index.js +9 -1
  15. package/cjs/positionData/index.d.ts +1 -1
  16. package/cjs/positionData/index.js +2 -2
  17. package/cjs/positionData/morpho.d.ts +1 -1
  18. package/cjs/positionData/morpho.js +15 -7
  19. package/cjs/safe/index.d.ts +6 -0
  20. package/cjs/safe/index.js +80 -0
  21. package/cjs/services/viem.d.ts +31 -31
  22. package/cjs/types/common.d.ts +10 -0
  23. package/cjs/types/exchange.d.ts +19 -0
  24. package/cjs/types/exchange.js +12 -0
  25. package/cjs/types/execution.d.ts +9 -0
  26. package/cjs/types/execution.js +8 -0
  27. package/cjs/types/index.d.ts +3 -0
  28. package/cjs/types/index.js +3 -0
  29. package/cjs/types/safe.d.ts +5 -0
  30. package/cjs/types/safe.js +2 -0
  31. package/esm/config/contracts.d.ts +181 -0
  32. package/esm/config/contracts.js +69 -0
  33. package/esm/constants/index.d.ts +7 -0
  34. package/esm/constants/index.js +7 -0
  35. package/esm/contracts.d.ts +696 -0
  36. package/esm/contracts.js +37 -0
  37. package/esm/exchange/index.d.ts +10 -0
  38. package/esm/exchange/index.js +176 -0
  39. package/esm/execution/index.d.ts +2 -0
  40. package/esm/execution/index.js +11 -0
  41. package/esm/execution/morpho.d.ts +2 -0
  42. package/esm/execution/morpho.js +52 -0
  43. package/esm/index.d.ts +5 -1
  44. package/esm/index.js +5 -1
  45. package/esm/positionData/index.d.ts +1 -1
  46. package/esm/positionData/index.js +2 -2
  47. package/esm/positionData/morpho.d.ts +1 -1
  48. package/esm/positionData/morpho.js +16 -8
  49. package/esm/safe/index.d.ts +6 -0
  50. package/esm/safe/index.js +75 -0
  51. package/esm/services/viem.d.ts +31 -31
  52. package/esm/types/common.d.ts +10 -0
  53. package/esm/types/exchange.d.ts +19 -0
  54. package/esm/types/exchange.js +9 -0
  55. package/esm/types/execution.d.ts +9 -0
  56. package/esm/types/execution.js +5 -0
  57. package/esm/types/index.d.ts +3 -0
  58. package/esm/types/index.js +3 -0
  59. package/esm/types/safe.d.ts +5 -0
  60. package/esm/types/safe.js +1 -0
  61. package/package.json +3 -1
  62. package/src/config/contracts.ts +72 -0
  63. package/src/constants/index.ts +7 -0
  64. package/src/contracts.ts +57 -0
  65. package/src/exchange/index.ts +195 -0
  66. package/src/execution/index.ts +12 -0
  67. package/src/execution/morpho.ts +47 -0
  68. package/src/index.ts +8 -0
  69. package/src/positionData/index.ts +2 -2
  70. package/src/positionData/morpho.ts +17 -8
  71. package/src/safe/index.ts +99 -0
  72. package/src/types/common.ts +11 -0
  73. package/src/types/exchange.ts +21 -0
  74. package/src/types/execution.ts +11 -0
  75. package/src/types/index.ts +4 -1
  76. package/src/types/safe.ts +5 -0
@@ -0,0 +1,37 @@
1
+ import { getContract } from 'viem';
2
+ import { NetworkNumber } from '@defisaver/positions-sdk';
3
+ import * as configRaw from './config/contracts';
4
+ // @ts-ignore
5
+ const contractConfig = configRaw;
6
+ export const getConfigContractAddress = (name, network) => {
7
+ const networkData = contractConfig[name].networks[network];
8
+ const latestAddress = (networkData === null || networkData === void 0 ? void 0 : networkData.address) || '';
9
+ return latestAddress;
10
+ };
11
+ export const getConfigContractAbi = (name) => {
12
+ const latestAbi = contractConfig[name].abi;
13
+ return latestAbi;
14
+ };
15
+ export const createContractFromConfigFunc = (name, _address) => (client, network) => {
16
+ const address = (_address || getConfigContractAddress(name, network));
17
+ const abi = getConfigContractAbi(name);
18
+ return getContract({
19
+ address,
20
+ abi,
21
+ client,
22
+ });
23
+ };
24
+ export const Safe130Contract = createContractFromConfigFunc('Safe130');
25
+ export const SafeFactoryContract = createContractFromConfigFunc('SafeProxyFactory130');
26
+ export const MorphoManagerContract = createContractFromConfigFunc('MorphoManager');
27
+ export const getSafeWalletContract = (client, address) => {
28
+ const abi = getConfigContractAbi('Safe130');
29
+ return getContract({
30
+ address,
31
+ abi,
32
+ client,
33
+ });
34
+ };
35
+ export const getSafeWalletSingletonAddress = (network) => getConfigContractAddress('Safe130', network || NetworkNumber.Eth);
36
+ export const getSafeFactoryAddress = (network) => getConfigContractAddress('SafeProxyFactory130', network || NetworkNumber.Eth);
37
+ export const getSafeFallbackHandlerAddress = (network) => getConfigContractAddress('SafeFallbackHandler130', network || NetworkNumber.Eth);
@@ -0,0 +1,10 @@
1
+ import { NetworkNumber } from '@defisaver/positions-sdk';
2
+ import { OffchainExchanges, PriceData } from '../types';
3
+ export declare const numStringToBytes: (num: number) => string;
4
+ export declare const getBestPrice: (fromAsset: string, toAsset: string, amount: string, userAddress: string, network?: NetworkNumber) => Promise<PriceData>;
5
+ export declare const getExchangeOrder: (fromAsset: string, toAsset: string, amount: string, userAddress: string, minPrice: string, network?: NetworkNumber) => Promise<{
6
+ orderData: (string | string[])[];
7
+ value: string;
8
+ source: OffchainExchanges | "None";
9
+ price: string;
10
+ }>;
@@ -0,0 +1,176 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import Dec from 'decimal.js';
11
+ import BN from 'bn.js';
12
+ import { NetworkNumber } from '@defisaver/positions-sdk';
13
+ import { assetAmountInWei, getAssetInfo } from '@defisaver/tokens';
14
+ import { OffchainExchanges } from '../types';
15
+ import { DFS_API_URL, SLIPPAGE_PERCENT, STABLE_PAIR_FEE_DIVIDER, ZERO_ADDRESS, } from '../constants';
16
+ const getOffchainEmptyData = (source = 'None') => ({
17
+ wrapper: ZERO_ADDRESS,
18
+ to: ZERO_ADDRESS,
19
+ allowanceTarget: ZERO_ADDRESS,
20
+ price: '0',
21
+ priceWithFee: '0',
22
+ protocolFee: '0',
23
+ data: '0x00',
24
+ value: '0',
25
+ gas: '0',
26
+ source,
27
+ });
28
+ const parsePriceWithDecimals = (price, fromDecimals, toDecimals) => new Dec(price)
29
+ .div(Math.pow(10, toDecimals))
30
+ .div(Math.pow(10, (18 - fromDecimals)))
31
+ .toString();
32
+ const formatPriceWithDecimalForContract = (price, fromDecimals, toDecimals) => new Dec(price)
33
+ .mul(Math.pow(10, toDecimals))
34
+ .mul(Math.pow(10, (18 - fromDecimals)))
35
+ .floor()
36
+ .toString();
37
+ const includeFeeInPrice = (price, from, to, fee) => {
38
+ if (from === to)
39
+ return price;
40
+ return new Dec(price).mul(new Dec(1).sub(fee)).toString();
41
+ };
42
+ const excludeFeeFromPrice = (price, from, to, fee) => {
43
+ if (from === to)
44
+ return price;
45
+ return new Dec(price).mul(new Dec(1).add(fee)).toString();
46
+ };
47
+ const parseOffchainPrice = (fromTokenSymbol, fromTokenDecimals, toTokenSymbol, toTokenDecimals, amount, feeDecimal) => {
48
+ const _price = parsePriceWithDecimals(amount, fromTokenDecimals, toTokenDecimals);
49
+ return includeFeeInPrice(_price, fromTokenSymbol, toTokenSymbol, feeDecimal);
50
+ };
51
+ const getFeeDecimal = () => new Dec(1).div(STABLE_PAIR_FEE_DIVIDER).toString();
52
+ export const numStringToBytes = (num) => {
53
+ const bn = new BN(num.toString()).toTwos(256);
54
+ return bn.toString(16);
55
+ };
56
+ const getPriceFromServer = (fromAsset_1, toAsset_1, amount_1, userAddress_1, ...args_1) => __awaiter(void 0, [fromAsset_1, toAsset_1, amount_1, userAddress_1, ...args_1], void 0, function* (fromAsset, toAsset, amount, userAddress, network = NetworkNumber.Eth, infoOnly = true) {
57
+ const fromAssetData = getAssetInfo(fromAsset, network);
58
+ const toAssetData = getAssetInfo(toAsset, network);
59
+ const feeDecimal = getFeeDecimal();
60
+ const excludedSources = ['Balancer_V2', 'Beethovenx'];
61
+ const allSources = Object.values(OffchainExchanges);
62
+ try {
63
+ const res = yield fetch(`${DFS_API_URL}/api/exchange/get-best-price`, {
64
+ method: 'POST',
65
+ headers: {
66
+ 'Content-Type': 'application/json',
67
+ },
68
+ body: JSON.stringify({
69
+ fromAsset: fromAssetData.address,
70
+ fromAssetDecimals: fromAssetData.decimals,
71
+ fromAssetSymbol: fromAssetData.symbol,
72
+ toAsset: toAssetData.address,
73
+ toAssetDecimals: toAssetData.decimals,
74
+ toAssetSymbol: toAssetData.symbol,
75
+ sources: [...allSources.map(s => s.toLowerCase())],
76
+ chainId: network,
77
+ amount,
78
+ excludedSources,
79
+ infoOnly,
80
+ takerAddress: userAddress,
81
+ account: userAddress,
82
+ noFee: false,
83
+ feeDecimal,
84
+ // temporary fix for paraswap until old exchange service is removed
85
+ shouldFormatParaswapPrice: true,
86
+ }),
87
+ });
88
+ if (!res.ok)
89
+ throw new Error(yield res.text());
90
+ const data = (yield res.json());
91
+ const formattedData = data.map((d, i) => {
92
+ const source = allSources[i];
93
+ if (typeof d === 'string')
94
+ return getOffchainEmptyData(source);
95
+ return {
96
+ wrapper: d.wrapper || ZERO_ADDRESS,
97
+ to: d.to || ZERO_ADDRESS,
98
+ allowanceTarget: d.allowanceTarget || ZERO_ADDRESS,
99
+ protocolFee: d.protocolFee || '0',
100
+ data: d.data || '0x00',
101
+ value: d.value || '0',
102
+ gas: d.gas || '0',
103
+ source: allSources[i],
104
+ price: d.price,
105
+ priceWithFee: +(d.price || '0') > 0
106
+ ? parseOffchainPrice(fromAssetData.symbol, fromAssetData.decimals, toAssetData.symbol, toAssetData.decimals, d.price, feeDecimal)
107
+ : '0',
108
+ };
109
+ }).filter((d) => d.wrapper !== ZERO_ADDRESS && d.price !== '0').sort((a, b) => (new Dec(a.price).gt(b.price) ? -1 : 1));
110
+ return formattedData;
111
+ }
112
+ catch (_a) {
113
+ return allSources.map(source => getOffchainEmptyData(source));
114
+ }
115
+ });
116
+ export const getBestPrice = (fromAsset_1, toAsset_1, amount_1, userAddress_1, ...args_1) => __awaiter(void 0, [fromAsset_1, toAsset_1, amount_1, userAddress_1, ...args_1], void 0, function* (fromAsset, toAsset, amount, userAddress, network = NetworkNumber.Eth) {
117
+ try {
118
+ const formattedData = yield getPriceFromServer(fromAsset, toAsset, amount, userAddress, network);
119
+ return formattedData[0] || getOffchainEmptyData();
120
+ }
121
+ catch (e) {
122
+ console.error('Error fetching best price:', e);
123
+ return getOffchainEmptyData();
124
+ }
125
+ });
126
+ export const getExchangeOrder = (fromAsset_1, toAsset_1, amount_1, userAddress_1, minPrice_1, ...args_1) => __awaiter(void 0, [fromAsset_1, toAsset_1, amount_1, userAddress_1, minPrice_1, ...args_1], void 0, function* (fromAsset, toAsset, amount, userAddress, minPrice, network = NetworkNumber.Eth) {
127
+ const fromAssetData = getAssetInfo(fromAsset, network);
128
+ const toAssetData = getAssetInfo(toAsset, network);
129
+ const feeDecimal = getFeeDecimal();
130
+ const offchainQuotes = yield getPriceFromServer(fromAsset, toAsset, amount, userAddress, network, false);
131
+ const formattedOffchainQuotes = offchainQuotes.map((quote) => ({
132
+ source: quote.source,
133
+ price: quote.priceWithFee,
134
+ wrapper: quote.wrapper,
135
+ wrapperData: quote.data,
136
+ offchainData: quote,
137
+ }));
138
+ const bestQuote = formattedOffchainQuotes[0];
139
+ const { offchainData, source, price } = bestQuote;
140
+ const minPriceFormatted = new Dec(excludeFeeFromPrice(minPrice, fromAssetData.address, toAssetData.address, feeDecimal))
141
+ .mul(100 - SLIPPAGE_PERCENT)
142
+ .div(100)
143
+ .toString();
144
+ const minPriceForContract = formatPriceWithDecimalForContract(minPriceFormatted, fromAssetData.decimals, toAssetData.decimals);
145
+ const offchainDataArray = [
146
+ offchainData.wrapper,
147
+ offchainData.to,
148
+ offchainData.allowanceTarget,
149
+ offchainData.price,
150
+ offchainData.protocolFee,
151
+ offchainData.data,
152
+ ];
153
+ const value = offchainData.protocolFee;
154
+ const wrapper = ZERO_ADDRESS;
155
+ const wrapperData = `0x${numStringToBytes(Math.floor(Date.now() / 1000))}`;
156
+ const amountWei = assetAmountInWei(amount, fromAsset).toString();
157
+ if (offchainData.data === '0x00')
158
+ throw new Error('Offchain data is empty');
159
+ return {
160
+ orderData: [
161
+ fromAssetData.address,
162
+ toAssetData.address,
163
+ amountWei,
164
+ '0',
165
+ minPriceForContract,
166
+ STABLE_PAIR_FEE_DIVIDER,
167
+ '0x0000000000000000000000000000000000000000', // set by contract
168
+ wrapper,
169
+ wrapperData,
170
+ offchainDataArray,
171
+ ],
172
+ value,
173
+ source,
174
+ price,
175
+ };
176
+ });
@@ -0,0 +1,2 @@
1
+ import { SupportedMarkets } from '../types';
2
+ export declare const getRequests: (market: SupportedMarkets) => import("../types").Request[];
@@ -0,0 +1,11 @@
1
+ import { SupportedMarkets } from '../types';
2
+ import { getMorphoRequests } from './morpho';
3
+ export const getRequests = (market) => {
4
+ switch (market) {
5
+ case SupportedMarkets.MorphoBlueSUSDeUSDtb_915: {
6
+ return getMorphoRequests();
7
+ }
8
+ default:
9
+ throw new Error(`Unsupported market: ${market}`);
10
+ }
11
+ };
@@ -0,0 +1,2 @@
1
+ import { Request } from '../types';
2
+ export declare const getMorphoRequests: () => Request[];
@@ -0,0 +1,52 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { MorphoManagerContract } from '../contracts';
11
+ import { getViemProvider } from '../services/viem';
12
+ import { RequestType } from '../types';
13
+ import { predictSafeAddress } from '../safe';
14
+ const morphoAuthSignature = {
15
+ type: RequestType.Signature,
16
+ getParams: (rpcUrl, network, userAddress) => __awaiter(void 0, void 0, void 0, function* () {
17
+ const provider = getViemProvider(rpcUrl, network);
18
+ const managerContract = MorphoManagerContract(provider, network);
19
+ const nonce = yield managerContract.read.nonce([userAddress]);
20
+ const tenMinutes = 1000 * 60 * 10;
21
+ const deadline = Date.now() + tenMinutes;
22
+ const safeAddress = yield predictSafeAddress(userAddress, rpcUrl, network);
23
+ return {
24
+ types: {
25
+ EIP712Domain: [
26
+ { name: 'verifyingContract', type: 'address' },
27
+ { name: 'chainId', type: 'uint256' },
28
+ ],
29
+ Authorization: [
30
+ { name: 'authorizer', type: 'address' },
31
+ { name: 'authorized', type: 'address' },
32
+ { name: 'isAuthorized', type: 'bool' },
33
+ { name: 'nonce', type: 'uint256' },
34
+ { name: 'deadline', type: 'uint256' },
35
+ ],
36
+ },
37
+ domain: {
38
+ chainId: network,
39
+ verifyingContract: managerContract.address,
40
+ },
41
+ primaryType: 'Authorization',
42
+ message: {
43
+ authorizer: userAddress,
44
+ authorized: safeAddress,
45
+ isAuthorized: true,
46
+ nonce: +nonce.toString(),
47
+ deadline,
48
+ },
49
+ };
50
+ }),
51
+ };
52
+ export const getMorphoRequests = () => [morphoAuthSignature];
package/esm/index.d.ts CHANGED
@@ -1,5 +1,9 @@
1
1
  import './setup';
2
2
  import * as positionData from './positionData';
3
3
  import * as marketData from './marketData';
4
+ import * as exchange from './exchange';
5
+ import * as constants from './constants';
6
+ import * as safe from './safe';
7
+ import * as execution from './execution';
4
8
  export * from './types';
5
- export { positionData, marketData, };
9
+ export { positionData, marketData, exchange, constants, safe, execution, };
package/esm/index.js CHANGED
@@ -1,5 +1,9 @@
1
1
  import './setup';
2
2
  import * as positionData from './positionData';
3
3
  import * as marketData from './marketData';
4
+ import * as exchange from './exchange';
5
+ import * as constants from './constants';
6
+ import * as safe from './safe';
7
+ import * as execution from './execution';
4
8
  export * from './types';
5
- export { positionData, marketData, };
9
+ export { positionData, marketData, exchange, constants, safe, execution, };
@@ -1,3 +1,3 @@
1
1
  import { MarketData, NetworkNumber, PositionData } from '../types';
2
2
  export declare const getMaxLeverageForSupplyAmount: (marketData: MarketData, supplyAmount: string) => number;
3
- export declare const getResultingPosition: (marketData: MarketData, supplyAmount: string, leverage: number, rpcUrl: string, network: NetworkNumber) => Promise<PositionData>;
3
+ export declare const getResultingPosition: (marketData: MarketData, supplyAmount: string, leverage: number, userAddress: string, rpcUrl: string, network: NetworkNumber) => Promise<PositionData>;
@@ -18,10 +18,10 @@ export const getMaxLeverageForSupplyAmount = (marketData, supplyAmount) => {
18
18
  throw new Error(`Unsupported market: ${marketData.market}`);
19
19
  }
20
20
  };
21
- export const getResultingPosition = (marketData, supplyAmount, leverage, rpcUrl, network) => __awaiter(void 0, void 0, void 0, function* () {
21
+ export const getResultingPosition = (marketData, supplyAmount, leverage, userAddress, rpcUrl, network) => __awaiter(void 0, void 0, void 0, function* () {
22
22
  switch (marketData.market) {
23
23
  case SupportedMarkets.MorphoBlueSUSDeUSDtb_915: {
24
- return getMorphoResultingPosition(marketData, supplyAmount, leverage, rpcUrl, network);
24
+ return getMorphoResultingPosition(marketData, supplyAmount, leverage, userAddress, rpcUrl, network);
25
25
  }
26
26
  default:
27
27
  throw new Error(`Unsupported market: ${marketData.market}`);
@@ -1,4 +1,4 @@
1
1
  import { NetworkNumber } from '@defisaver/positions-sdk';
2
2
  import { MarketData, PositionData } from '../types';
3
3
  export declare const getMorphoMaxLeverageForSupplyAmount: (marketData: MarketData, supplyAmount: string) => number;
4
- export declare const getMorphoResultingPosition: (marketData: MarketData, supplyAmount: string, leverage: number, rpcUrl: string, network: NetworkNumber) => Promise<PositionData>;
4
+ export declare const getMorphoResultingPosition: (marketData: MarketData, supplyAmount: string, leverage: number, userAddress: string, rpcUrl: string, network: NetworkNumber) => Promise<PositionData>;
@@ -8,9 +8,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import Dec from 'decimal.js';
11
- import { getAssetInfo } from '@defisaver/tokens';
11
+ import { assetAmountInWei, getAssetInfo } from '@defisaver/tokens';
12
12
  import { helpers, markets, morphoBlue, MorphoBlueVersions, } from '@defisaver/positions-sdk';
13
13
  import { getViemProvider } from '../services/viem';
14
+ import { getBestPrice } from '../exchange';
14
15
  const getMaxBoostUsd = (lltv, borrowLimit, debt, targetRatio = 1.01, bufferPercent = 1) => new Dec(targetRatio).mul(debt).sub(borrowLimit)
15
16
  .div(new Dec(lltv).sub(targetRatio).toString())
16
17
  .mul((100 - bufferPercent) / 100)
@@ -30,19 +31,19 @@ export const getMorphoMaxLeverageForSupplyAmount = (marketData, supplyAmount) =>
30
31
  const maxLeverage = new Dec(supplyAmount).plus(new Dec(maxDebt).times(rate)).div(supplyAmount).toNumber();
31
32
  return maxLeverage;
32
33
  };
33
- export const getMorphoResultingPosition = (marketData, supplyAmount, leverage, rpcUrl, network) => __awaiter(void 0, void 0, void 0, function* () {
34
+ export const getMorphoResultingPosition = (marketData, supplyAmount, leverage, userAddress, rpcUrl, network) => __awaiter(void 0, void 0, void 0, function* () {
34
35
  const provider = getViemProvider(rpcUrl, network);
35
36
  const morphoMarket = markets.MorphoBlueMarkets(network)[MorphoBlueVersions.MorphoBlueSUSDeUSDtb_915];
36
37
  const { rate: oracle, assetsData, } = marketData;
38
+ const supplyAsset = Object.values(assetsData).find((asset) => !asset.isDebtAsset);
39
+ const borrowAsset = Object.values(assetsData).find((asset) => asset.isDebtAsset);
37
40
  const debtAmount = new Dec(leverage)
38
41
  .times(supplyAmount).minus(supplyAmount).times(oracle)
39
42
  .toString();
40
- // TODO: add price fetching logic
41
- const priceForAmount = new Dec(1).div(oracle).toString();
42
- const leveragedAmount = new Dec(debtAmount).times(priceForAmount);
43
+ const debtAmountWei = assetAmountInWei(debtAmount, borrowAsset.symbol);
44
+ const { priceWithFee, source } = yield getBestPrice(borrowAsset.symbol, supplyAsset.symbol, debtAmountWei, userAddress, network);
45
+ const leveragedAmount = new Dec(debtAmount).times(priceWithFee);
43
46
  const collIncrease = new Dec(supplyAmount).plus(leveragedAmount).toString();
44
- const supplyAsset = Object.values(assetsData).find((asset) => !asset.isDebtAsset);
45
- const borrowAsset = Object.values(assetsData).find((asset) => asset.isDebtAsset);
46
47
  const morphoMarketData = yield morphoBlue._getMorphoBlueMarketData(provider, network, morphoMarket);
47
48
  const usedAssets = {};
48
49
  usedAssets[borrowAsset.symbol] = {
@@ -66,5 +67,12 @@ export const getMorphoResultingPosition = (marketData, supplyAmount, leverage, r
66
67
  borrowedUsd: '0',
67
68
  };
68
69
  const aggregatedPosition = helpers.morphoBlueHelpers.getMorphoBlueAggregatedPositionData({ usedAssets, assetsData: morphoMarketData.assetsData, marketInfo: morphoMarketData });
69
- return Object.assign({ usedAssets }, aggregatedPosition);
70
+ return Object.assign({ exchangeInfo: {
71
+ price: priceWithFee,
72
+ source,
73
+ sellAsset: borrowAsset.symbol,
74
+ sellAmount: debtAmount,
75
+ buyAsset: supplyAsset.symbol,
76
+ buyAmount: leveragedAmount.toString(),
77
+ }, usedAssets }, aggregatedPosition);
70
78
  });
@@ -0,0 +1,6 @@
1
+ import { NetworkNumber } from '@defisaver/positions-sdk';
2
+ export declare const getSafeWallets: (userAddress: string, network: NetworkNumber) => Promise<{
3
+ success: boolean;
4
+ wallets: string[];
5
+ }>;
6
+ export declare const predictSafeAddress: (owner: string, rpcUrl: string, network: NetworkNumber) => Promise<string>;
@@ -0,0 +1,75 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { encodeFunctionData, encodePacked, getCreate2Address, keccak256, } from 'viem';
11
+ import { SAFE_API_URL, SAFE_REFUND_RECEIVER, SALT_PREFIX, ZERO_ADDRESS, } from '../constants';
12
+ import { getConfigContractAbi, getSafeFactoryAddress, getSafeFallbackHandlerAddress, getSafeWalletSingletonAddress, SafeFactoryContract, } from '../contracts';
13
+ import { getViemProvider } from '../services/viem';
14
+ export const getSafeWallets = (userAddress, network) => __awaiter(void 0, void 0, void 0, function* () {
15
+ try {
16
+ const res = yield fetch(`${SAFE_API_URL}/safe/all-wallets?network=${network}&account=${userAddress}`);
17
+ const wallets = yield res.json();
18
+ const oneOneWallets = wallets
19
+ .filter((wallet) => wallet.type === 'Safe' && (wallet.owners || []).length === 1)
20
+ .map((wallet) => wallet.address);
21
+ return { success: true, wallets: oneOneWallets };
22
+ }
23
+ catch (e) {
24
+ return { success: false, wallets: [] };
25
+ }
26
+ });
27
+ const getSafeSetupParams = (owners, threshold, network) => [
28
+ owners,
29
+ BigInt(threshold),
30
+ ZERO_ADDRESS,
31
+ '0x',
32
+ getSafeFallbackHandlerAddress(network),
33
+ ZERO_ADDRESS,
34
+ BigInt(0),
35
+ SAFE_REFUND_RECEIVER,
36
+ ];
37
+ const _predictSafeAddress = (rpcUrl, network, setupArgs, saltNonce) => __awaiter(void 0, void 0, void 0, function* () {
38
+ const provider = getViemProvider(rpcUrl, network);
39
+ const safeProxyFactoryAddress = getSafeFactoryAddress(network);
40
+ const safeProxyFactoryContract = SafeFactoryContract(provider, network);
41
+ const masterCopyAddress = getSafeWalletSingletonAddress(network);
42
+ const proxyCreationCode = yield safeProxyFactoryContract.read.proxyCreationCode();
43
+ // @ts-ignore
44
+ const initCodeHash = keccak256(encodePacked(['bytes', 'bytes'], [proxyCreationCode, masterCopyAddress.slice(2).padStart(64, '0')]), 'bytes');
45
+ const salt = keccak256(encodePacked(['bytes', 'uint256'], [keccak256(setupArgs), BigInt(saltNonce)]));
46
+ return getCreate2Address({
47
+ bytecodeHash: initCodeHash,
48
+ from: safeProxyFactoryAddress,
49
+ salt,
50
+ });
51
+ });
52
+ export const predictSafeAddress = (owner, rpcUrl, network) => __awaiter(void 0, void 0, void 0, function* () {
53
+ const provider = getViemProvider(rpcUrl, network);
54
+ const threshold = 1;
55
+ const owners = [owner];
56
+ const setupParams = getSafeSetupParams(owners, threshold, network);
57
+ const setupParamsEncoded = encodeFunctionData({
58
+ abi: getConfigContractAbi('Safe130'),
59
+ functionName: 'setup',
60
+ // @ts-ignore
61
+ args: setupParams,
62
+ });
63
+ const oneOfOneWalletsCount = (yield getSafeWallets(owner, network)).wallets.length;
64
+ const failAfter = 10;
65
+ for (let nonce = oneOfOneWalletsCount + 1; nonce < oneOfOneWalletsCount + failAfter + 1; nonce += 1) {
66
+ const salt = `${SALT_PREFIX}${nonce}`;
67
+ const predictedAddr = yield _predictSafeAddress(rpcUrl, network, setupParamsEncoded, salt);
68
+ const bytecode = yield provider.getCode({ address: predictedAddr });
69
+ if (!bytecode) {
70
+ // safe does not exist
71
+ return predictedAddr;
72
+ }
73
+ }
74
+ return '';
75
+ });