@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.
- package/cjs/config/contracts.d.ts +181 -0
- package/cjs/config/contracts.js +72 -0
- package/cjs/constants/index.d.ts +7 -0
- package/cjs/constants/index.js +10 -0
- package/cjs/contracts.d.ts +696 -0
- package/cjs/contracts.js +80 -0
- package/cjs/exchange/index.d.ts +10 -0
- package/cjs/exchange/index.js +185 -0
- package/cjs/execution/index.d.ts +2 -0
- package/cjs/execution/index.js +15 -0
- package/cjs/execution/morpho.d.ts +2 -0
- package/cjs/execution/morpho.js +56 -0
- package/cjs/index.d.ts +5 -1
- package/cjs/index.js +9 -1
- package/cjs/positionData/index.d.ts +1 -1
- package/cjs/positionData/index.js +2 -2
- package/cjs/positionData/morpho.d.ts +1 -1
- package/cjs/positionData/morpho.js +15 -7
- package/cjs/safe/index.d.ts +6 -0
- package/cjs/safe/index.js +80 -0
- package/cjs/services/viem.d.ts +31 -31
- package/cjs/types/common.d.ts +10 -0
- package/cjs/types/exchange.d.ts +19 -0
- package/cjs/types/exchange.js +12 -0
- package/cjs/types/execution.d.ts +9 -0
- package/cjs/types/execution.js +8 -0
- package/cjs/types/index.d.ts +3 -0
- package/cjs/types/index.js +3 -0
- package/cjs/types/safe.d.ts +5 -0
- package/cjs/types/safe.js +2 -0
- package/esm/config/contracts.d.ts +181 -0
- package/esm/config/contracts.js +69 -0
- package/esm/constants/index.d.ts +7 -0
- package/esm/constants/index.js +7 -0
- package/esm/contracts.d.ts +696 -0
- package/esm/contracts.js +37 -0
- package/esm/exchange/index.d.ts +10 -0
- package/esm/exchange/index.js +176 -0
- package/esm/execution/index.d.ts +2 -0
- package/esm/execution/index.js +11 -0
- package/esm/execution/morpho.d.ts +2 -0
- package/esm/execution/morpho.js +52 -0
- package/esm/index.d.ts +5 -1
- package/esm/index.js +5 -1
- package/esm/positionData/index.d.ts +1 -1
- package/esm/positionData/index.js +2 -2
- package/esm/positionData/morpho.d.ts +1 -1
- package/esm/positionData/morpho.js +16 -8
- package/esm/safe/index.d.ts +6 -0
- package/esm/safe/index.js +75 -0
- package/esm/services/viem.d.ts +31 -31
- package/esm/types/common.d.ts +10 -0
- package/esm/types/exchange.d.ts +19 -0
- package/esm/types/exchange.js +9 -0
- package/esm/types/execution.d.ts +9 -0
- package/esm/types/execution.js +5 -0
- package/esm/types/index.d.ts +3 -0
- package/esm/types/index.js +3 -0
- package/esm/types/safe.d.ts +5 -0
- package/esm/types/safe.js +1 -0
- package/package.json +3 -1
- package/src/config/contracts.ts +72 -0
- package/src/constants/index.ts +7 -0
- package/src/contracts.ts +57 -0
- package/src/exchange/index.ts +195 -0
- package/src/execution/index.ts +12 -0
- package/src/execution/morpho.ts +47 -0
- package/src/index.ts +8 -0
- package/src/positionData/index.ts +2 -2
- package/src/positionData/morpho.ts +17 -8
- package/src/safe/index.ts +99 -0
- package/src/types/common.ts +11 -0
- package/src/types/exchange.ts +21 -0
- package/src/types/execution.ts +11 -0
- package/src/types/index.ts +4 -1
- package/src/types/safe.ts +5 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { NetworkNumber } from '@defisaver/positions-sdk';
|
|
2
|
+
import { MorphoManagerContract } from '../contracts';
|
|
3
|
+
import { getViemProvider } from '../services/viem';
|
|
4
|
+
import { Request, RequestType } from '../types';
|
|
5
|
+
import { predictSafeAddress } from '../safe';
|
|
6
|
+
|
|
7
|
+
const morphoAuthSignature: Request = {
|
|
8
|
+
type: RequestType.Signature,
|
|
9
|
+
getParams: async (rpcUrl: string, network: NetworkNumber, userAddress: string) => {
|
|
10
|
+
const provider = getViemProvider(rpcUrl, network);
|
|
11
|
+
const managerContract = MorphoManagerContract(provider, network);
|
|
12
|
+
const nonce = await managerContract.read.nonce([userAddress as `0x${string}`]);
|
|
13
|
+
const tenMinutes = 1000 * 60 * 10;
|
|
14
|
+
const deadline = Date.now() + tenMinutes;
|
|
15
|
+
const safeAddress = await predictSafeAddress(userAddress, rpcUrl, network);
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
types: {
|
|
19
|
+
EIP712Domain: [
|
|
20
|
+
{ name: 'verifyingContract', type: 'address' },
|
|
21
|
+
{ name: 'chainId', type: 'uint256' },
|
|
22
|
+
],
|
|
23
|
+
Authorization: [
|
|
24
|
+
{ name: 'authorizer', type: 'address' },
|
|
25
|
+
{ name: 'authorized', type: 'address' },
|
|
26
|
+
{ name: 'isAuthorized', type: 'bool' },
|
|
27
|
+
{ name: 'nonce', type: 'uint256' },
|
|
28
|
+
{ name: 'deadline', type: 'uint256' },
|
|
29
|
+
],
|
|
30
|
+
},
|
|
31
|
+
domain: {
|
|
32
|
+
chainId: network,
|
|
33
|
+
verifyingContract: managerContract.address,
|
|
34
|
+
},
|
|
35
|
+
primaryType: 'Authorization',
|
|
36
|
+
message: {
|
|
37
|
+
authorizer: userAddress,
|
|
38
|
+
authorized: safeAddress,
|
|
39
|
+
isAuthorized: true,
|
|
40
|
+
nonce: +nonce.toString(),
|
|
41
|
+
deadline,
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const getMorphoRequests = () => [morphoAuthSignature];
|
package/src/index.ts
CHANGED
|
@@ -2,10 +2,18 @@ import './setup';
|
|
|
2
2
|
|
|
3
3
|
import * as positionData from './positionData';
|
|
4
4
|
import * as marketData from './marketData';
|
|
5
|
+
import * as exchange from './exchange';
|
|
6
|
+
import * as constants from './constants';
|
|
7
|
+
import * as safe from './safe';
|
|
8
|
+
import * as execution from './execution';
|
|
5
9
|
|
|
6
10
|
export * from './types';
|
|
7
11
|
|
|
8
12
|
export {
|
|
9
13
|
positionData,
|
|
10
14
|
marketData,
|
|
15
|
+
exchange,
|
|
16
|
+
constants,
|
|
17
|
+
safe,
|
|
18
|
+
execution,
|
|
11
19
|
};
|
|
@@ -13,10 +13,10 @@ export const getMaxLeverageForSupplyAmount = (marketData: MarketData, supplyAmou
|
|
|
13
13
|
}
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
export const getResultingPosition = async (marketData: MarketData, supplyAmount: string, leverage: number, rpcUrl: string, network: NetworkNumber): Promise<PositionData> => {
|
|
16
|
+
export const getResultingPosition = async (marketData: MarketData, supplyAmount: string, leverage: number, userAddress: string, rpcUrl: string, network: NetworkNumber): Promise<PositionData> => {
|
|
17
17
|
switch (marketData.market) {
|
|
18
18
|
case SupportedMarkets.MorphoBlueSUSDeUSDtb_915: {
|
|
19
|
-
return getMorphoResultingPosition(marketData, supplyAmount, leverage, rpcUrl, network);
|
|
19
|
+
return getMorphoResultingPosition(marketData, supplyAmount, leverage, userAddress, rpcUrl, network);
|
|
20
20
|
}
|
|
21
21
|
default:
|
|
22
22
|
throw new Error(`Unsupported market: ${marketData.market}`);
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import Dec from 'decimal.js';
|
|
2
|
-
import { getAssetInfo } from '@defisaver/tokens';
|
|
2
|
+
import { assetAmountInWei, getAssetInfo } from '@defisaver/tokens';
|
|
3
3
|
import {
|
|
4
4
|
helpers, markets, MMUsedAssets, morphoBlue, MorphoBlueVersions, NetworkNumber,
|
|
5
5
|
} from '@defisaver/positions-sdk';
|
|
6
6
|
import { AssetData, MarketData, PositionData } from '../types';
|
|
7
7
|
import { getViemProvider } from '../services/viem';
|
|
8
|
+
import { getBestPrice } from '../exchange';
|
|
8
9
|
|
|
9
10
|
const getMaxBoostUsd = (lltv: string, borrowLimit: string, debt: string, targetRatio = 1.01, bufferPercent = 1) => new Dec(targetRatio).mul(debt).sub(borrowLimit)
|
|
10
11
|
.div(new Dec(lltv).sub(targetRatio).toString())
|
|
@@ -38,24 +39,24 @@ export const getMorphoMaxLeverageForSupplyAmount = (marketData: MarketData, supp
|
|
|
38
39
|
return maxLeverage;
|
|
39
40
|
};
|
|
40
41
|
|
|
41
|
-
export const getMorphoResultingPosition = async (marketData: MarketData, supplyAmount: string, leverage: number, rpcUrl: string, network: NetworkNumber): Promise<PositionData> => {
|
|
42
|
+
export const getMorphoResultingPosition = async (marketData: MarketData, supplyAmount: string, leverage: number, userAddress: string, rpcUrl: string, network: NetworkNumber): Promise<PositionData> => {
|
|
42
43
|
const provider = getViemProvider(rpcUrl, network);
|
|
43
44
|
|
|
44
45
|
const morphoMarket = markets.MorphoBlueMarkets(network)[MorphoBlueVersions.MorphoBlueSUSDeUSDtb_915];
|
|
45
46
|
const {
|
|
46
47
|
rate: oracle, assetsData,
|
|
47
48
|
} = marketData;
|
|
49
|
+
const supplyAsset: AssetData = Object.values(assetsData).find((asset) => !asset.isDebtAsset)!;
|
|
50
|
+
const borrowAsset: AssetData = Object.values(assetsData).find((asset) => asset.isDebtAsset)!;
|
|
48
51
|
const debtAmount = new Dec(leverage)
|
|
49
52
|
.times(supplyAmount).minus(supplyAmount).times(oracle)
|
|
50
53
|
.toString();
|
|
51
54
|
|
|
52
|
-
|
|
53
|
-
const
|
|
54
|
-
const leveragedAmount = new Dec(debtAmount).times(priceForAmount);
|
|
55
|
-
const collIncrease = new Dec(supplyAmount).plus(leveragedAmount).toString();
|
|
55
|
+
const debtAmountWei = assetAmountInWei(debtAmount, borrowAsset.symbol);
|
|
56
|
+
const { priceWithFee, source } = await getBestPrice(borrowAsset.symbol, supplyAsset.symbol, debtAmountWei, userAddress, network);
|
|
56
57
|
|
|
57
|
-
const
|
|
58
|
-
const
|
|
58
|
+
const leveragedAmount = new Dec(debtAmount).times(priceWithFee);
|
|
59
|
+
const collIncrease = new Dec(supplyAmount).plus(leveragedAmount).toString();
|
|
59
60
|
|
|
60
61
|
const morphoMarketData = await morphoBlue._getMorphoBlueMarketData(provider, network, morphoMarket);
|
|
61
62
|
const usedAssets: MMUsedAssets = {};
|
|
@@ -84,6 +85,14 @@ export const getMorphoResultingPosition = async (marketData: MarketData, supplyA
|
|
|
84
85
|
|
|
85
86
|
const aggregatedPosition = helpers.morphoBlueHelpers.getMorphoBlueAggregatedPositionData({ usedAssets, assetsData: morphoMarketData.assetsData, marketInfo: morphoMarketData });
|
|
86
87
|
return {
|
|
88
|
+
exchangeInfo: {
|
|
89
|
+
price: priceWithFee,
|
|
90
|
+
source,
|
|
91
|
+
sellAsset: borrowAsset.symbol,
|
|
92
|
+
sellAmount: debtAmount,
|
|
93
|
+
buyAsset: supplyAsset.symbol,
|
|
94
|
+
buyAmount: leveragedAmount.toString(),
|
|
95
|
+
},
|
|
87
96
|
usedAssets,
|
|
88
97
|
...aggregatedPosition,
|
|
89
98
|
};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { NetworkNumber } from '@defisaver/positions-sdk';
|
|
2
|
+
import {
|
|
3
|
+
encodeFunctionData, encodePacked, getCreate2Address, keccak256,
|
|
4
|
+
} from 'viem';
|
|
5
|
+
import { Wallet } from '../types';
|
|
6
|
+
import {
|
|
7
|
+
SAFE_API_URL, SAFE_REFUND_RECEIVER, SALT_PREFIX, ZERO_ADDRESS,
|
|
8
|
+
} from '../constants';
|
|
9
|
+
import {
|
|
10
|
+
getConfigContractAbi,
|
|
11
|
+
getSafeFactoryAddress, getSafeFallbackHandlerAddress, getSafeWalletSingletonAddress, SafeFactoryContract,
|
|
12
|
+
} from '../contracts';
|
|
13
|
+
import { getViemProvider } from '../services/viem';
|
|
14
|
+
|
|
15
|
+
export const getSafeWallets = async (userAddress: string, network: NetworkNumber): Promise<{ success: boolean, wallets: string[] }> => {
|
|
16
|
+
try {
|
|
17
|
+
const res = await fetch(`${SAFE_API_URL}/safe/all-wallets?network=${network}&account=${userAddress}`);
|
|
18
|
+
const wallets = await res.json();
|
|
19
|
+
|
|
20
|
+
const oneOneWallets = wallets
|
|
21
|
+
.filter((wallet: Wallet) => wallet.type === 'Safe' && (wallet.owners || []).length === 1)
|
|
22
|
+
.map((wallet: Wallet) => wallet.address);
|
|
23
|
+
return { success: true, wallets: oneOneWallets };
|
|
24
|
+
} catch (e) {
|
|
25
|
+
return { success: false, wallets: [] };
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const getSafeSetupParams = (owners: string[], threshold: number, network: NetworkNumber) => [
|
|
30
|
+
owners as `0x${string}`[],
|
|
31
|
+
BigInt(threshold),
|
|
32
|
+
ZERO_ADDRESS as `0x${string}`,
|
|
33
|
+
'0x',
|
|
34
|
+
getSafeFallbackHandlerAddress(network) as `0x${string}`,
|
|
35
|
+
ZERO_ADDRESS as `0x${string}`,
|
|
36
|
+
BigInt(0),
|
|
37
|
+
SAFE_REFUND_RECEIVER as `0x${string}`,
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
const _predictSafeAddress = async (
|
|
41
|
+
rpcUrl: string,
|
|
42
|
+
network: NetworkNumber,
|
|
43
|
+
setupArgs: string,
|
|
44
|
+
saltNonce: string,
|
|
45
|
+
) => {
|
|
46
|
+
const provider = getViemProvider(rpcUrl, network);
|
|
47
|
+
const safeProxyFactoryAddress = getSafeFactoryAddress(network);
|
|
48
|
+
const safeProxyFactoryContract = SafeFactoryContract(provider, network);
|
|
49
|
+
const masterCopyAddress = getSafeWalletSingletonAddress(network);
|
|
50
|
+
|
|
51
|
+
const proxyCreationCode = await safeProxyFactoryContract.read.proxyCreationCode();
|
|
52
|
+
|
|
53
|
+
// @ts-ignore
|
|
54
|
+
const initCodeHash = keccak256(
|
|
55
|
+
encodePacked(['bytes', 'bytes'], [proxyCreationCode, masterCopyAddress.slice(2).padStart(64, '0') as `0x${string}`]), 'bytes',
|
|
56
|
+
) as string;
|
|
57
|
+
|
|
58
|
+
const salt = keccak256(
|
|
59
|
+
encodePacked(
|
|
60
|
+
['bytes', 'uint256'],
|
|
61
|
+
[keccak256(setupArgs as `0x${string}`), BigInt(saltNonce)],
|
|
62
|
+
),
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
return getCreate2Address(
|
|
66
|
+
{
|
|
67
|
+
bytecodeHash: initCodeHash as `0x${string}`,
|
|
68
|
+
from: safeProxyFactoryAddress,
|
|
69
|
+
salt,
|
|
70
|
+
},
|
|
71
|
+
);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export const predictSafeAddress = async (owner: string, rpcUrl: string, network: NetworkNumber): Promise<string> => {
|
|
75
|
+
const provider = getViemProvider(rpcUrl, network);
|
|
76
|
+
|
|
77
|
+
const threshold = 1;
|
|
78
|
+
const owners = [owner];
|
|
79
|
+
const setupParams = getSafeSetupParams(owners, threshold, network);
|
|
80
|
+
const setupParamsEncoded = encodeFunctionData({
|
|
81
|
+
abi: getConfigContractAbi('Safe130'),
|
|
82
|
+
functionName: 'setup',
|
|
83
|
+
// @ts-ignore
|
|
84
|
+
args: setupParams,
|
|
85
|
+
});
|
|
86
|
+
const oneOfOneWalletsCount = (await getSafeWallets(owner, network)).wallets.length;
|
|
87
|
+
const failAfter = 10;
|
|
88
|
+
for (let nonce = oneOfOneWalletsCount + 1; nonce < oneOfOneWalletsCount + failAfter + 1; nonce += 1) {
|
|
89
|
+
const salt = `${SALT_PREFIX}${nonce}`;
|
|
90
|
+
const predictedAddr = await _predictSafeAddress(rpcUrl, network, setupParamsEncoded, salt);
|
|
91
|
+
const bytecode = await provider.getCode({ address: predictedAddr });
|
|
92
|
+
if (!bytecode) {
|
|
93
|
+
// safe does not exist
|
|
94
|
+
return predictedAddr;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return '';
|
|
99
|
+
};
|
package/src/types/common.ts
CHANGED
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
IncentiveData, MMUsedAssets, MorphoBlueAggregatedPositionData, NetworkNumber,
|
|
3
3
|
} from '@defisaver/positions-sdk';
|
|
4
4
|
import { SupportedMarkets } from './markets';
|
|
5
|
+
import { OffchainExchanges } from './exchange';
|
|
5
6
|
|
|
6
7
|
export interface AssetData {
|
|
7
8
|
symbol: string;
|
|
@@ -23,8 +24,18 @@ export interface MarketData {
|
|
|
23
24
|
rate: string;
|
|
24
25
|
}
|
|
25
26
|
|
|
27
|
+
export interface ExchangeInfo {
|
|
28
|
+
price: string;
|
|
29
|
+
source: OffchainExchanges | 'None';
|
|
30
|
+
sellAsset: string;
|
|
31
|
+
sellAmount: string;
|
|
32
|
+
buyAsset: string;
|
|
33
|
+
buyAmount: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
26
36
|
export interface PositionData extends MorphoBlueAggregatedPositionData {
|
|
27
37
|
usedAssets: MMUsedAssets;
|
|
38
|
+
exchangeInfo: ExchangeInfo;
|
|
28
39
|
}
|
|
29
40
|
|
|
30
41
|
export {
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export enum OffchainExchanges {
|
|
2
|
+
ZeroX = '0x',
|
|
3
|
+
Paraswap = 'Paraswap',
|
|
4
|
+
Kyberswap = 'Kyberswap',
|
|
5
|
+
OneInch = '1Inch',
|
|
6
|
+
// Odos = 'Odos',
|
|
7
|
+
Bebop = 'Bebop',
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface PriceData {
|
|
11
|
+
price: string;
|
|
12
|
+
priceWithFee: string;
|
|
13
|
+
source: OffchainExchanges | 'None';
|
|
14
|
+
wrapper: string;
|
|
15
|
+
to: string;
|
|
16
|
+
allowanceTarget: string;
|
|
17
|
+
protocolFee: string;
|
|
18
|
+
data: string;
|
|
19
|
+
value: string;
|
|
20
|
+
gas: string;
|
|
21
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { NetworkNumber } from '@defisaver/positions-sdk';
|
|
2
|
+
|
|
3
|
+
export enum RequestType {
|
|
4
|
+
Signature = 'Signature',
|
|
5
|
+
EthCall = 'EthCall',
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface Request {
|
|
9
|
+
type: RequestType;
|
|
10
|
+
getParams: (rpcUrl: string, network: NetworkNumber, userAddress: string) => Promise<any>;
|
|
11
|
+
}
|
package/src/types/index.ts
CHANGED