@dhedge/v2-sdk 1.5.4 → 1.7.0
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/config.d.ts +2 -1
- package/dist/entities/pool.d.ts +21 -1
- package/dist/entities/utils.d.ts +7 -2
- package/dist/services/lyra/markets.d.ts +6 -0
- package/dist/services/lyra/positions.d.ts +2 -0
- package/dist/services/lyra/quote.d.ts +4 -0
- package/dist/services/lyra/trade.d.ts +4 -0
- package/dist/services/lyra/tradeOptionType.d.ts +3 -0
- package/dist/test/constants.d.ts +1 -0
- package/dist/types.d.ts +20 -1
- package/dist/v2-sdk.cjs.development.js +4202 -12
- package/dist/v2-sdk.cjs.development.js.map +1 -1
- package/dist/v2-sdk.cjs.production.min.js +1 -1
- package/dist/v2-sdk.cjs.production.min.js.map +1 -1
- package/dist/v2-sdk.esm.js +4200 -11
- package/dist/v2-sdk.esm.js.map +1 -1
- package/package.json +6 -2
- package/src/abi/IOptionMArketWrapper.json +1038 -0
- package/src/abi/IOptionMarket.json +1473 -0
- package/src/abi/IOptionToken.json +1671 -0
- package/src/config.ts +10 -5
- package/src/entities/pool.ts +61 -1
- package/src/entities/utils.ts +45 -2
- package/src/services/lyra/markets.ts +52 -0
- package/src/services/lyra/positions.ts +19 -0
- package/src/services/lyra/quote.ts +12 -0
- package/src/services/lyra/trade.ts +101 -0
- package/src/services/lyra/tradeOptionType.ts +19 -0
- package/src/test/constants.ts +1 -0
- package/src/test/lyra.test.ts +163 -0
- package/src/test/pool.test.ts +1 -1
- package/src/test/toros.test.ts +1 -1
- package/src/test/txOptions.ts +1 -1
- package/src/test/uniswap.test.ts +1 -1
- package/src/test/velodrome.test.ts +1 -1
- package/src/test/wallet.ts +8 -0
- package/src/types.ts +20 -1
- package/src/test/sushi.test.ts +0 -173
package/src/config.ts
CHANGED
|
@@ -2,9 +2,11 @@ import {
|
|
|
2
2
|
Dapp,
|
|
3
3
|
AddressNetworkMap,
|
|
4
4
|
Network,
|
|
5
|
-
AddressDappNetworkMap
|
|
5
|
+
AddressDappNetworkMap,
|
|
6
|
+
LyraNetworkMap
|
|
6
7
|
} from "./types";
|
|
7
8
|
import { NetworkChainIdMap } from ".";
|
|
9
|
+
import { Deployment } from "@lyrafinance/lyra-js";
|
|
8
10
|
|
|
9
11
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
10
12
|
require("dotenv").config();
|
|
@@ -34,7 +36,8 @@ export const routerAddress: AddressDappNetworkMap = {
|
|
|
34
36
|
[Dapp.AAVEV3]: "0x794a61358D6845594F94dc1DB02A252b5b4814aD",
|
|
35
37
|
[Dapp.ONEINCH]: "0x1111111254760F7ab3F16433eea9304126DCd199",
|
|
36
38
|
[Dapp.TOROS]: "0xf8C62BD5f2fEf9E1a329c197F32E77AD6866B022",
|
|
37
|
-
[Dapp.VELODROME]: "0x9c12939390052919aF3155f41Bf4160Fd3666A6f"
|
|
39
|
+
[Dapp.VELODROME]: "0x9c12939390052919aF3155f41Bf4160Fd3666A6f",
|
|
40
|
+
[Dapp.LYRA]: "0xCCE7819d65f348c64B7Beb205BA367b3fE33763B"
|
|
38
41
|
}
|
|
39
42
|
};
|
|
40
43
|
|
|
@@ -53,9 +56,7 @@ export const stakingAddress: AddressDappNetworkMap = {
|
|
|
53
56
|
[Dapp.AAVE]: "0x357D51124f59836DeD84c8a1730D72B749d8BC23",
|
|
54
57
|
[Dapp.AAVEV3]: "0x929EC64c34a17401F460460D4B9390518E5B473e"
|
|
55
58
|
},
|
|
56
|
-
[Network.OPTIMISM]: {
|
|
57
|
-
[Dapp.AAVEV3]: "0x929EC64c34a17401F460460D4B9390518E5B473e"
|
|
58
|
-
}
|
|
59
|
+
[Network.OPTIMISM]: {}
|
|
59
60
|
};
|
|
60
61
|
|
|
61
62
|
export const aaveAddressProvider: AddressDappNetworkMap = {
|
|
@@ -88,6 +89,10 @@ export const multiCallAddress: AddressNetworkMap = {
|
|
|
88
89
|
[Network.OPTIMISM]: ""
|
|
89
90
|
};
|
|
90
91
|
|
|
92
|
+
export const lyraNetworkMap: LyraNetworkMap = {
|
|
93
|
+
[Network.OPTIMISM]: Deployment.Mainnet
|
|
94
|
+
};
|
|
95
|
+
|
|
91
96
|
export const deadline = Math.floor(Date.now() / 1000) + 60 * 20;
|
|
92
97
|
export const MaxUint128 = "0xffffffffffffffffffffffffffffffff";
|
|
93
98
|
export const UNISWAPV3_QUOTER_ADDRESS =
|
package/src/entities/pool.ts
CHANGED
|
@@ -29,7 +29,11 @@ import {
|
|
|
29
29
|
Transaction,
|
|
30
30
|
FundComposition,
|
|
31
31
|
AssetEnabled,
|
|
32
|
-
Network
|
|
32
|
+
Network,
|
|
33
|
+
LyraOptionMarket,
|
|
34
|
+
LyraOptionType,
|
|
35
|
+
LyraTradeType,
|
|
36
|
+
LyraPosition
|
|
33
37
|
} from "../types";
|
|
34
38
|
|
|
35
39
|
import { Utils } from "./utils";
|
|
@@ -51,6 +55,8 @@ import {
|
|
|
51
55
|
getVelodromeClaimTxData,
|
|
52
56
|
getVelodromeStakeTxData
|
|
53
57
|
} from "../services/velodrome/staking";
|
|
58
|
+
import { getLyraOptionTxData } from "../services/lyra/trade";
|
|
59
|
+
import { getOptionPositions } from "../services/lyra/positions";
|
|
54
60
|
|
|
55
61
|
export class Pool {
|
|
56
62
|
public readonly poolLogic: Contract;
|
|
@@ -1165,4 +1171,58 @@ export class Pool {
|
|
|
1165
1171
|
);
|
|
1166
1172
|
return tx;
|
|
1167
1173
|
}
|
|
1174
|
+
|
|
1175
|
+
/**
|
|
1176
|
+
* Trade options on lyra
|
|
1177
|
+
* @param {LyraOptionMarket} market Underlying market e.g. eth
|
|
1178
|
+
* @param {number} expiry Expiry timestamp
|
|
1179
|
+
* @param { number} strike Strike price
|
|
1180
|
+
* @param {LyraOptionType} optionType Call or put
|
|
1181
|
+
* @param { LyraTradeType} tradeType By or sell
|
|
1182
|
+
* @param {BigNumber | string } optionAmount Option amount
|
|
1183
|
+
* @param {string } assetIn Asset to invest
|
|
1184
|
+
* @param {BigNumber | string } collateralChangeAmount Collateral amount to add when shorting options and to remove when covering shorts
|
|
1185
|
+
* @param {boolean} isCoveredCall Selling covered call options
|
|
1186
|
+
* @param {any} options Transaction options
|
|
1187
|
+
* @returns {Promise<any>} Transaction
|
|
1188
|
+
*/
|
|
1189
|
+
async tradeLyraOption(
|
|
1190
|
+
market: LyraOptionMarket,
|
|
1191
|
+
expiry: number,
|
|
1192
|
+
strike: number,
|
|
1193
|
+
optionType: LyraOptionType,
|
|
1194
|
+
tradeType: LyraTradeType,
|
|
1195
|
+
optionAmount: BigNumber | string,
|
|
1196
|
+
assetIn: string,
|
|
1197
|
+
collateralChangeAmount: BigNumber | string = "0",
|
|
1198
|
+
isCoveredCall = false,
|
|
1199
|
+
options: any = null
|
|
1200
|
+
): Promise<any> {
|
|
1201
|
+
const swapxData = await getLyraOptionTxData(
|
|
1202
|
+
this,
|
|
1203
|
+
market,
|
|
1204
|
+
optionType,
|
|
1205
|
+
expiry,
|
|
1206
|
+
strike,
|
|
1207
|
+
tradeType,
|
|
1208
|
+
optionAmount,
|
|
1209
|
+
assetIn,
|
|
1210
|
+
BigNumber.from(collateralChangeAmount),
|
|
1211
|
+
isCoveredCall
|
|
1212
|
+
);
|
|
1213
|
+
const tx = await this.poolLogic.execTransaction(
|
|
1214
|
+
routerAddress[this.network][Dapp.LYRA],
|
|
1215
|
+
swapxData,
|
|
1216
|
+
options
|
|
1217
|
+
);
|
|
1218
|
+
return tx;
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
/**
|
|
1222
|
+
* Gets Lyra option positions
|
|
1223
|
+
* @returns {Promise<Position>} Transaction
|
|
1224
|
+
*/
|
|
1225
|
+
async getLyraPositions(market: LyraOptionMarket): Promise<LyraPosition[]> {
|
|
1226
|
+
return await getOptionPositions(this, market);
|
|
1227
|
+
}
|
|
1168
1228
|
}
|
package/src/entities/utils.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Contract, ethers, Wallet } from "ethers";
|
|
1
|
+
import { BigNumber, Contract, ethers, Wallet } from "ethers";
|
|
2
2
|
import {
|
|
3
3
|
Token,
|
|
4
4
|
TokenAmount,
|
|
@@ -22,8 +22,18 @@ import {
|
|
|
22
22
|
networkChainIdMap,
|
|
23
23
|
stakingAddress
|
|
24
24
|
} from "../config";
|
|
25
|
-
import {
|
|
25
|
+
import {
|
|
26
|
+
Dapp,
|
|
27
|
+
LyraOptionMarket,
|
|
28
|
+
LyraOptionType,
|
|
29
|
+
LyraTradeType,
|
|
30
|
+
Network,
|
|
31
|
+
Reserves
|
|
32
|
+
} from "../types";
|
|
26
33
|
import { Pool } from ".";
|
|
34
|
+
import { getExpiries, getStrike, getStrikes } from "../services/lyra/markets";
|
|
35
|
+
import { Quote, Strike } from "@lyrafinance/lyra-js";
|
|
36
|
+
import { getQuote } from "../services/lyra/quote";
|
|
27
37
|
|
|
28
38
|
export class Utils {
|
|
29
39
|
network: Network;
|
|
@@ -328,4 +338,37 @@ export class Utils {
|
|
|
328
338
|
const exitPoolTx = iBalancerV2Vault.encodeFunctionData("exitPool", txData);
|
|
329
339
|
return exitPoolTx;
|
|
330
340
|
}
|
|
341
|
+
|
|
342
|
+
async getLyraOptionExpiries(market: LyraOptionMarket): Promise<number[]> {
|
|
343
|
+
return await getExpiries(this.network, market);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
async getLyraOptionStrikes(
|
|
347
|
+
market: LyraOptionMarket,
|
|
348
|
+
expiry: number
|
|
349
|
+
): Promise<Strike[]> {
|
|
350
|
+
return await getStrikes(this.network, market, expiry);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
async getLyraOptionStrike(
|
|
354
|
+
market: LyraOptionMarket,
|
|
355
|
+
expiry: number,
|
|
356
|
+
strike: number
|
|
357
|
+
): Promise<Strike> {
|
|
358
|
+
return await getStrike(this.network, market, expiry, strike);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
async getLyraOptionQuote(
|
|
362
|
+
strike: Strike,
|
|
363
|
+
type: LyraOptionType,
|
|
364
|
+
tradeType: LyraTradeType,
|
|
365
|
+
amount: BigNumber | string
|
|
366
|
+
): Promise<Quote> {
|
|
367
|
+
return await getQuote(
|
|
368
|
+
strike,
|
|
369
|
+
type,
|
|
370
|
+
tradeType,
|
|
371
|
+
ethers.BigNumber.from(amount)
|
|
372
|
+
);
|
|
373
|
+
}
|
|
331
374
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import { ethers, LyraOptionMarket, Network } from "../..";
|
|
3
|
+
import { lyraNetworkMap } from "../../config";
|
|
4
|
+
import Lyra, { Board, Strike } from "@lyrafinance/lyra-js";
|
|
5
|
+
|
|
6
|
+
export async function getBoard(
|
|
7
|
+
network: Network,
|
|
8
|
+
market: LyraOptionMarket,
|
|
9
|
+
expiry: number
|
|
10
|
+
): Promise<Board> {
|
|
11
|
+
const lyra = new Lyra(lyraNetworkMap[network]);
|
|
12
|
+
const optionMarket = await lyra.market(market);
|
|
13
|
+
const filteredBoards = optionMarket
|
|
14
|
+
.liveBoards()
|
|
15
|
+
.filter(e => e.expiryTimestamp === expiry);
|
|
16
|
+
if (filteredBoards.length === 0) throw new Error("no lyra board for expiry");
|
|
17
|
+
return filteredBoards[0];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export async function getExpiries(
|
|
21
|
+
network: Network,
|
|
22
|
+
market: LyraOptionMarket
|
|
23
|
+
): Promise<number[]> {
|
|
24
|
+
const lyra = new Lyra(lyraNetworkMap[network]);
|
|
25
|
+
const optionMarket = await lyra.market(market);
|
|
26
|
+
return optionMarket.liveBoards().map(e => e.expiryTimestamp);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function getStrikes(
|
|
30
|
+
network: Network,
|
|
31
|
+
market: LyraOptionMarket,
|
|
32
|
+
expiry: number
|
|
33
|
+
): Promise<Strike[]> {
|
|
34
|
+
return (await getBoard(network, market, expiry)).strikes();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export async function getStrike(
|
|
38
|
+
network: Network,
|
|
39
|
+
market: LyraOptionMarket,
|
|
40
|
+
expiry: number,
|
|
41
|
+
strike: number
|
|
42
|
+
): Promise<Strike> {
|
|
43
|
+
const strikes = await getStrikes(network, market, expiry);
|
|
44
|
+
const filteredStrike = strikes.filter(
|
|
45
|
+
(e: Strike) =>
|
|
46
|
+
parseFloat(ethers.utils.formatEther(e.strikePrice)) === strike
|
|
47
|
+
);
|
|
48
|
+
if (filteredStrike.length === 0)
|
|
49
|
+
throw new Error("no option found for strike price");
|
|
50
|
+
|
|
51
|
+
return filteredStrike[0];
|
|
52
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import { ethers, LyraOptionMarket, LyraPosition, Pool } from "../..";
|
|
3
|
+
import Lyra from "@lyrafinance/lyra-js";
|
|
4
|
+
import IOptionToken from "../../abi/IOptionToken.json";
|
|
5
|
+
|
|
6
|
+
export async function getOptionPositions(
|
|
7
|
+
pool: Pool,
|
|
8
|
+
market: LyraOptionMarket
|
|
9
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
10
|
+
): Promise<LyraPosition[]> {
|
|
11
|
+
const lyra = new Lyra();
|
|
12
|
+
const optionMarket = await lyra.market(market);
|
|
13
|
+
const iOptionToken = new ethers.Contract(
|
|
14
|
+
optionMarket.__marketData.marketAddresses.optionToken,
|
|
15
|
+
IOptionToken.abi,
|
|
16
|
+
pool.signer
|
|
17
|
+
);
|
|
18
|
+
return await iOptionToken.getOwnerPositions(pool.address);
|
|
19
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Quote, Strike } from "@lyrafinance/lyra-js";
|
|
2
|
+
import { ethers } from "ethers";
|
|
3
|
+
import { LyraOptionType, LyraTradeType } from "../../types";
|
|
4
|
+
|
|
5
|
+
export async function getQuote(
|
|
6
|
+
strike: Strike,
|
|
7
|
+
type: LyraOptionType,
|
|
8
|
+
tradeType: LyraTradeType,
|
|
9
|
+
amount: ethers.BigNumber
|
|
10
|
+
): Promise<Quote> {
|
|
11
|
+
return await strike.quote(type === "call", tradeType === "buy", amount);
|
|
12
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import { BigNumber, ethers } from "ethers";
|
|
3
|
+
import { Pool } from "../..";
|
|
4
|
+
import { LyraOptionMarket, LyraOptionType, LyraTradeType } from "../../types";
|
|
5
|
+
import { getStrike } from "./markets";
|
|
6
|
+
import IOptionMarketWrapper from "../../abi/IOptionMarketWrapper.json";
|
|
7
|
+
import { getLyraTradeOptionType, isCall, isLong } from "./tradeOptionType";
|
|
8
|
+
import { getOptionPositions } from "./positions";
|
|
9
|
+
import { getQuote } from "./quote";
|
|
10
|
+
|
|
11
|
+
export async function getLyraOptionTxData(
|
|
12
|
+
pool: Pool,
|
|
13
|
+
market: LyraOptionMarket,
|
|
14
|
+
optionType: LyraOptionType,
|
|
15
|
+
expiry: number,
|
|
16
|
+
strikePrice: number,
|
|
17
|
+
tradeType: LyraTradeType,
|
|
18
|
+
optionAmount: BigNumber | string,
|
|
19
|
+
assetIn: string,
|
|
20
|
+
collateralAmount: BigNumber,
|
|
21
|
+
isCoveredCall: boolean
|
|
22
|
+
): Promise<string> {
|
|
23
|
+
const strike = await getStrike(pool.network, market, expiry, strikePrice);
|
|
24
|
+
const strikeId = strike.id;
|
|
25
|
+
|
|
26
|
+
const positions = await getOptionPositions(pool, market);
|
|
27
|
+
const filteredPosition = positions.filter(
|
|
28
|
+
e =>
|
|
29
|
+
e.strikeId.toNumber() === strikeId &&
|
|
30
|
+
isCall(e.optionType) == (optionType === "call") &&
|
|
31
|
+
e.state === 1
|
|
32
|
+
);
|
|
33
|
+
const positionId =
|
|
34
|
+
filteredPosition.length > 0 ? filteredPosition[0].positionId : 0;
|
|
35
|
+
|
|
36
|
+
let lyraOptionType = getLyraTradeOptionType(
|
|
37
|
+
optionType === "call",
|
|
38
|
+
tradeType === "buy",
|
|
39
|
+
isCoveredCall
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
const amountIn = BigNumber.from(optionAmount);
|
|
43
|
+
const quote = await getQuote(strike, optionType, tradeType, amountIn);
|
|
44
|
+
const netPremiun =
|
|
45
|
+
tradeType === "buy"
|
|
46
|
+
? quote.premium.add(quote.fee)
|
|
47
|
+
: quote.premium.sub(quote.fee);
|
|
48
|
+
|
|
49
|
+
let txFunction = "openPosition";
|
|
50
|
+
let inputAmount = tradeType === "buy" ? netPremiun : collateralAmount;
|
|
51
|
+
let currentCollateral = BigNumber.from(0);
|
|
52
|
+
let setCollateral = collateralAmount;
|
|
53
|
+
if (filteredPosition.length > 0) {
|
|
54
|
+
currentCollateral = filteredPosition[0].collateral ?? BigNumber.from(0);
|
|
55
|
+
setCollateral = currentCollateral.add(collateralAmount);
|
|
56
|
+
if (
|
|
57
|
+
//sell long positions
|
|
58
|
+
(tradeType === "sell" && isLong(filteredPosition[0].optionType)) ||
|
|
59
|
+
//cover short positions
|
|
60
|
+
(tradeType === "buy" && !isLong(filteredPosition[0].optionType))
|
|
61
|
+
) {
|
|
62
|
+
lyraOptionType = filteredPosition[0].optionType;
|
|
63
|
+
txFunction = "closePosition";
|
|
64
|
+
setCollateral = currentCollateral.sub(collateralAmount);
|
|
65
|
+
//cover short
|
|
66
|
+
if (
|
|
67
|
+
!isLong(filteredPosition[0].optionType) &&
|
|
68
|
+
!isCoveredCall &&
|
|
69
|
+
collateralAmount.gt(netPremiun)
|
|
70
|
+
) {
|
|
71
|
+
inputAmount = netPremiun.sub(collateralAmount);
|
|
72
|
+
} else if (!isLong(filteredPosition[0].optionType) && isCoveredCall) {
|
|
73
|
+
inputAmount = netPremiun;
|
|
74
|
+
} else {
|
|
75
|
+
inputAmount = BigNumber.from(0);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const iOptionMarketWrapper = new ethers.utils.Interface(
|
|
81
|
+
IOptionMarketWrapper.abi
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const tradeTx = iOptionMarketWrapper.encodeFunctionData(txFunction, [
|
|
85
|
+
[
|
|
86
|
+
strike.market().contractAddresses.optionMarket,
|
|
87
|
+
strikeId, // strike Id
|
|
88
|
+
positionId, // position Id
|
|
89
|
+
1, // iteration
|
|
90
|
+
setCollateral, // set collateral to
|
|
91
|
+
currentCollateral, // current collateral
|
|
92
|
+
lyraOptionType, // optionType
|
|
93
|
+
amountIn, // amount
|
|
94
|
+
tradeType === "sell" ? netPremiun : 0, // min cost
|
|
95
|
+
tradeType === "buy" ? netPremiun : ethers.constants.MaxUint256, // max cost
|
|
96
|
+
inputAmount,
|
|
97
|
+
assetIn // input asset
|
|
98
|
+
]
|
|
99
|
+
]);
|
|
100
|
+
return tradeTx;
|
|
101
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export function getLyraTradeOptionType(
|
|
2
|
+
isCall: boolean,
|
|
3
|
+
isLong: boolean,
|
|
4
|
+
isCoveredCall: boolean
|
|
5
|
+
): number {
|
|
6
|
+
if (isCall) {
|
|
7
|
+
return isLong ? 0 : isCoveredCall ? 2 : 3;
|
|
8
|
+
} else {
|
|
9
|
+
return isLong ? 1 : 4;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function isCall(optionType: number): boolean {
|
|
14
|
+
return [0, 2, 3].includes(optionType);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function isLong(optionType: number): boolean {
|
|
18
|
+
return optionType === 0 || optionType === 1;
|
|
19
|
+
}
|
package/src/test/constants.ts
CHANGED
|
@@ -28,5 +28,6 @@ export const WBTC = "0x68f180fcCe6836688e9084f035309E29Bf0A2095";
|
|
|
28
28
|
export const OP = "4200000000000000000000000000000000000042";
|
|
29
29
|
export const WSTETH = "0x1F32b1c2345538c0c6f582fCB022739c4A194Ebb";
|
|
30
30
|
export const VEL = "0x3c8B650257cFb5f272f799F5e2b4e65093a11a05";
|
|
31
|
+
export const SUSD = "0x8c6f28f2f1a3c87f0f938b96d27520d9751ec8d9";
|
|
31
32
|
|
|
32
33
|
export const TEST_POOL = "TEST_POOL";
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { Dhedge } from "..";
|
|
2
|
+
import { Network } from "../types";
|
|
3
|
+
import { utils } from "ethers";
|
|
4
|
+
import { SUSD, TEST_POOL } from "./constants";
|
|
5
|
+
import { getTxOptions } from "./txOptions";
|
|
6
|
+
import { wallet } from "./wallet";
|
|
7
|
+
|
|
8
|
+
jest.setTimeout(100000);
|
|
9
|
+
|
|
10
|
+
describe("pool", () => {
|
|
11
|
+
let dhedge: Dhedge;
|
|
12
|
+
const options = getTxOptions(Network.OPTIMISM);
|
|
13
|
+
beforeAll(async () => {
|
|
14
|
+
dhedge = new Dhedge(wallet, Network.OPTIMISM);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it("buys 0.1 1400 calls with expiry October 28th", async () => {
|
|
18
|
+
let result;
|
|
19
|
+
const pool = await dhedge.loadPool(TEST_POOL);
|
|
20
|
+
try {
|
|
21
|
+
result = await pool.tradeLyraOption(
|
|
22
|
+
"eth",
|
|
23
|
+
1666944000,
|
|
24
|
+
1400,
|
|
25
|
+
"call",
|
|
26
|
+
"buy",
|
|
27
|
+
utils.parseEther("0.1"),
|
|
28
|
+
SUSD
|
|
29
|
+
);
|
|
30
|
+
} catch (e) {
|
|
31
|
+
console.log(e);
|
|
32
|
+
}
|
|
33
|
+
result.wait(1);
|
|
34
|
+
const positions = await pool.getLyraPositions("eth");
|
|
35
|
+
expect(positions.length > 0);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("adds 0.05 1400 calls with expiry October 28th", async () => {
|
|
39
|
+
let result;
|
|
40
|
+
const pool = await dhedge.loadPool(TEST_POOL);
|
|
41
|
+
try {
|
|
42
|
+
result = await pool.tradeLyraOption(
|
|
43
|
+
"eth",
|
|
44
|
+
1666944000,
|
|
45
|
+
1400,
|
|
46
|
+
"call",
|
|
47
|
+
"buy",
|
|
48
|
+
utils.parseEther("0.05"),
|
|
49
|
+
SUSD,
|
|
50
|
+
"0",
|
|
51
|
+
false,
|
|
52
|
+
options
|
|
53
|
+
);
|
|
54
|
+
} catch (e) {
|
|
55
|
+
console.log(e);
|
|
56
|
+
}
|
|
57
|
+
result.wait(1);
|
|
58
|
+
const positions = await pool.getLyraPositions("eth");
|
|
59
|
+
expect(utils.formatEther(positions[0].amount)).toBe("0.15");
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("sells 0.1 1300 Covered Call with expiry October 28th", async () => {
|
|
63
|
+
let result;
|
|
64
|
+
const pool = await dhedge.loadPool(TEST_POOL);
|
|
65
|
+
try {
|
|
66
|
+
result = await pool.tradeLyraOption(
|
|
67
|
+
"eth",
|
|
68
|
+
1666944000,
|
|
69
|
+
1300,
|
|
70
|
+
"call",
|
|
71
|
+
"sell",
|
|
72
|
+
utils.parseEther("0.1"),
|
|
73
|
+
SUSD,
|
|
74
|
+
utils.parseEther("0.1"),
|
|
75
|
+
true,
|
|
76
|
+
options
|
|
77
|
+
);
|
|
78
|
+
} catch (e) {
|
|
79
|
+
console.log(e);
|
|
80
|
+
}
|
|
81
|
+
result.wait(1);
|
|
82
|
+
const positions = await pool.getLyraPositions("eth");
|
|
83
|
+
const cCall = positions.find(e => e.optionType === 2);
|
|
84
|
+
expect(cCall).not.toBe(undefined);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("adds 0.05 1300 Covered Call with expiry October 28th", async () => {
|
|
88
|
+
let result;
|
|
89
|
+
const pool = await dhedge.loadPool(TEST_POOL);
|
|
90
|
+
try {
|
|
91
|
+
result = await pool.tradeLyraOption(
|
|
92
|
+
"eth",
|
|
93
|
+
1666944000,
|
|
94
|
+
1300,
|
|
95
|
+
"call",
|
|
96
|
+
"sell",
|
|
97
|
+
utils.parseEther("0.05"),
|
|
98
|
+
SUSD,
|
|
99
|
+
utils.parseEther("0.05"),
|
|
100
|
+
true,
|
|
101
|
+
options
|
|
102
|
+
);
|
|
103
|
+
} catch (e) {
|
|
104
|
+
console.log(e);
|
|
105
|
+
}
|
|
106
|
+
result.wait(1);
|
|
107
|
+
const positions = await pool.getLyraPositions("eth");
|
|
108
|
+
const cCall = positions.find(e => e.optionType === 2);
|
|
109
|
+
expect(cCall);
|
|
110
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
111
|
+
expect(utils.formatEther(cCall!.amount)).toBe("0.15");
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it("closes all 0.15 1300 Covered Call with expiry October 28th", async () => {
|
|
115
|
+
let result;
|
|
116
|
+
const pool = await dhedge.loadPool(TEST_POOL);
|
|
117
|
+
try {
|
|
118
|
+
result = await pool.tradeLyraOption(
|
|
119
|
+
"eth",
|
|
120
|
+
1666944000,
|
|
121
|
+
1300,
|
|
122
|
+
"call",
|
|
123
|
+
"buy",
|
|
124
|
+
utils.parseEther("0.15"),
|
|
125
|
+
SUSD,
|
|
126
|
+
utils.parseEther("0.15"),
|
|
127
|
+
true,
|
|
128
|
+
options
|
|
129
|
+
);
|
|
130
|
+
} catch (e) {
|
|
131
|
+
console.log(e);
|
|
132
|
+
}
|
|
133
|
+
result.wait(1);
|
|
134
|
+
const positions = await pool.getLyraPositions("eth");
|
|
135
|
+
const cCall = positions.find(e => e.optionType === 2 && e.state === 1);
|
|
136
|
+
expect(cCall).toBe(undefined);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it("closes all 0.15 1400 Calls with expiry October 28th", async () => {
|
|
140
|
+
let result;
|
|
141
|
+
const pool = await dhedge.loadPool(TEST_POOL);
|
|
142
|
+
try {
|
|
143
|
+
result = await pool.tradeLyraOption(
|
|
144
|
+
"eth",
|
|
145
|
+
1666944000,
|
|
146
|
+
1400,
|
|
147
|
+
"call",
|
|
148
|
+
"sell",
|
|
149
|
+
utils.parseEther("0.15"),
|
|
150
|
+
SUSD,
|
|
151
|
+
"0",
|
|
152
|
+
false,
|
|
153
|
+
options
|
|
154
|
+
);
|
|
155
|
+
} catch (e) {
|
|
156
|
+
console.log(e);
|
|
157
|
+
}
|
|
158
|
+
result.wait(1);
|
|
159
|
+
const positions = await pool.getLyraPositions("eth");
|
|
160
|
+
const call = positions.find(e => e.optionType === 0 && e.state === 1);
|
|
161
|
+
expect(call).toBe(undefined);
|
|
162
|
+
});
|
|
163
|
+
});
|
package/src/test/pool.test.ts
CHANGED
package/src/test/toros.test.ts
CHANGED
|
@@ -25,7 +25,7 @@ describe("pool", () => {
|
|
|
25
25
|
let result;
|
|
26
26
|
const pool = await dhedge.loadPool(ETHBULL3X);
|
|
27
27
|
try {
|
|
28
|
-
const depositAsset = await getPoolDepositAsset(pool, ETHBULL3X);
|
|
28
|
+
const depositAsset = await getPoolDepositAsset(pool, ETHBULL3X, USDC);
|
|
29
29
|
if (!depositAsset) throw new Error("no deposit assets");
|
|
30
30
|
|
|
31
31
|
result = await getEasySwapperDepositQuote(
|
package/src/test/txOptions.ts
CHANGED
package/src/test/uniswap.test.ts
CHANGED
|
@@ -13,7 +13,7 @@ jest.setTimeout(100000);
|
|
|
13
13
|
describe("pool", () => {
|
|
14
14
|
beforeAll(async () => {
|
|
15
15
|
dhedge = new Dhedge(wallet, Network.POLYGON);
|
|
16
|
-
options = await getTxOptions();
|
|
16
|
+
options = await getTxOptions(Network.POLYGON);
|
|
17
17
|
//options = { gasLimit: "3000000" };
|
|
18
18
|
});
|
|
19
19
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
import { Dhedge, ethers } from "..";
|
|
3
3
|
import { Dapp, Network } from "../types";
|
|
4
|
-
import { TEST_POOL, WETH, WSTETH } from "./constants";
|
|
4
|
+
import { TEST_POOL, VEL, WETH, WSTETH } from "./constants";
|
|
5
5
|
import { getTxOptions } from "./txOptions";
|
|
6
6
|
|
|
7
7
|
import { wallet } from "./wallet";
|
package/src/test/wallet.ts
CHANGED
|
@@ -7,6 +7,14 @@ const provider = new ethers.providers.JsonRpcProvider(
|
|
|
7
7
|
`https://opt-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_PROJECT_ID}`
|
|
8
8
|
);
|
|
9
9
|
|
|
10
|
+
// const provider = new ethers.providers.JsonRpcProvider(
|
|
11
|
+
// `https://opt-kovan.g.alchemy.com/v2/${process.env.ALCHEMY_PROJECT_ID}`
|
|
12
|
+
// );
|
|
13
|
+
|
|
14
|
+
// const provider = new ethers.providers.JsonRpcProvider(
|
|
15
|
+
// `https://polygon-mainnet.infura.io/v3/${process.env.INFURA_PROJECT_ID}`
|
|
16
|
+
// );
|
|
17
|
+
|
|
10
18
|
// const provider = new ethers.providers.JsonRpcProvider(
|
|
11
19
|
// `https://polygon-mainnet.infura.io/v3/${process.env.INFURA_PROJECT_ID}`
|
|
12
20
|
// );
|
package/src/types.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Deployment } from "@lyrafinance/lyra-js";
|
|
1
2
|
import { BigNumber } from "ethers";
|
|
2
3
|
|
|
3
4
|
export enum Network {
|
|
@@ -16,7 +17,8 @@ export enum Dapp {
|
|
|
16
17
|
AAVEV3 = "aavev3",
|
|
17
18
|
ARRAKIS = "arrakis",
|
|
18
19
|
TOROS = "toros",
|
|
19
|
-
VELODROME = "velodrome"
|
|
20
|
+
VELODROME = "velodrome",
|
|
21
|
+
LYRA = "lyra"
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
export enum Transaction {
|
|
@@ -69,3 +71,20 @@ export type Reserves = {
|
|
|
69
71
|
};
|
|
70
72
|
|
|
71
73
|
export type NetworkChainIdMap = Readonly<Record<Network, number>>;
|
|
74
|
+
|
|
75
|
+
export type LyraOptionMarket = "eth";
|
|
76
|
+
export type AddressMarketMap = {
|
|
77
|
+
[key in LyraOptionMarket]: string;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export type LyraTradeType = "buy" | "sell";
|
|
81
|
+
export type LyraOptionType = "call" | "put";
|
|
82
|
+
export type LyraNetworkMap = { [key in Network]?: Deployment };
|
|
83
|
+
export type LyraPosition = {
|
|
84
|
+
positionId: BigNumber;
|
|
85
|
+
strikeId: BigNumber;
|
|
86
|
+
optionType: number;
|
|
87
|
+
amount: BigNumber;
|
|
88
|
+
collateral: BigNumber;
|
|
89
|
+
state: number;
|
|
90
|
+
};
|