@dhedge/v2-sdk 1.10.9 → 1.10.11
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/dhedge.d.ts +1 -1
- package/dist/entities/pool.d.ts +2 -1
- package/dist/services/flatmoney/stableLp.d.ts +1 -0
- package/dist/services/odos/index.d.ts +3 -0
- package/dist/test/constants.d.ts +4 -0
- package/dist/types.d.ts +2 -1
- package/dist/v2-sdk.cjs.development.js +354 -61
- 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 +354 -61
- package/dist/v2-sdk.esm.js.map +1 -1
- package/package.json +2 -2
- package/src/abi/flatmoney/v2/IOrderExecutionModule.json +96 -0
- package/src/config.ts +18 -6
- package/src/entities/dhedge.ts +5 -4
- package/src/entities/pool.ts +14 -1
- package/src/services/flatmoney/keeperFee.ts +12 -4
- package/src/services/flatmoney/stableLp.ts +30 -8
- package/src/services/odos/index.ts +61 -0
- package/src/test/constants.ts +6 -1
- package/src/test/flatmoney.test.ts +30 -11
- package/src/test/odos.test.ts +109 -0
- package/src/types.ts +2 -1
- package/src/utils/contract.ts +19 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dhedge/v2-sdk",
|
|
3
|
-
"version": "1.10.
|
|
3
|
+
"version": "1.10.11",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "🛠 An SDK for building applications on top of dHEDGE V2",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"@size-limit/preset-small-lib": "^5.0.1",
|
|
35
35
|
"@types/jest": "^28.1.7",
|
|
36
36
|
"@types/lodash": "^4.14.178",
|
|
37
|
-
"hardhat": "2.
|
|
37
|
+
"hardhat": "2.23.0",
|
|
38
38
|
"husky": "^7.0.1",
|
|
39
39
|
"jest": "^28.1.3",
|
|
40
40
|
"size-limit": "^5.0.1",
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"type": "function",
|
|
4
|
+
"name": "cancelExistingOrder",
|
|
5
|
+
"inputs": [
|
|
6
|
+
{
|
|
7
|
+
"name": "account",
|
|
8
|
+
"type": "address",
|
|
9
|
+
"internalType": "address"
|
|
10
|
+
}
|
|
11
|
+
],
|
|
12
|
+
"outputs": [],
|
|
13
|
+
"stateMutability": "nonpayable"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"type": "function",
|
|
17
|
+
"name": "cancelOrderByModule",
|
|
18
|
+
"inputs": [
|
|
19
|
+
{
|
|
20
|
+
"name": "account",
|
|
21
|
+
"type": "address",
|
|
22
|
+
"internalType": "address"
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
"outputs": [],
|
|
26
|
+
"stateMutability": "nonpayable"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"type": "function",
|
|
30
|
+
"name": "executeLimitOrder",
|
|
31
|
+
"inputs": [
|
|
32
|
+
{
|
|
33
|
+
"name": "tokenId",
|
|
34
|
+
"type": "uint256",
|
|
35
|
+
"internalType": "uint256"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"name": "priceUpdateData",
|
|
39
|
+
"type": "bytes[]",
|
|
40
|
+
"internalType": "bytes[]"
|
|
41
|
+
}
|
|
42
|
+
],
|
|
43
|
+
"outputs": [],
|
|
44
|
+
"stateMutability": "payable"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"type": "function",
|
|
48
|
+
"name": "executeOrder",
|
|
49
|
+
"inputs": [
|
|
50
|
+
{
|
|
51
|
+
"name": "account",
|
|
52
|
+
"type": "address",
|
|
53
|
+
"internalType": "address"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"name": "priceUpdateData",
|
|
57
|
+
"type": "bytes[]",
|
|
58
|
+
"internalType": "bytes[]"
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
"outputs": [],
|
|
62
|
+
"stateMutability": "payable"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"type": "function",
|
|
66
|
+
"name": "hasOrderExpired",
|
|
67
|
+
"inputs": [
|
|
68
|
+
{
|
|
69
|
+
"name": "account",
|
|
70
|
+
"type": "address",
|
|
71
|
+
"internalType": "address"
|
|
72
|
+
}
|
|
73
|
+
],
|
|
74
|
+
"outputs": [
|
|
75
|
+
{
|
|
76
|
+
"name": "expired",
|
|
77
|
+
"type": "bool",
|
|
78
|
+
"internalType": "bool"
|
|
79
|
+
}
|
|
80
|
+
],
|
|
81
|
+
"stateMutability": "view"
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"type": "function",
|
|
85
|
+
"name": "maxExecutabilityAge",
|
|
86
|
+
"inputs": [],
|
|
87
|
+
"outputs": [
|
|
88
|
+
{
|
|
89
|
+
"name": "maxExecutabilityAge",
|
|
90
|
+
"type": "uint64",
|
|
91
|
+
"internalType": "uint64"
|
|
92
|
+
}
|
|
93
|
+
],
|
|
94
|
+
"stateMutability": "view"
|
|
95
|
+
}
|
|
96
|
+
]
|
package/src/config.ts
CHANGED
|
@@ -31,7 +31,8 @@ export const routerAddress: AddressDappNetworkMap = {
|
|
|
31
31
|
[Dapp.UNISWAPV3]: "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45",
|
|
32
32
|
[Dapp.ARRAKIS]: "0xc73fb100a995b33f9fa181d420f4c8d74506df66",
|
|
33
33
|
[Dapp.TOROS]: "0x45b90480D6F643dE2f128db091A357C3c90399f2",
|
|
34
|
-
[Dapp.ZEROEX]: "0xdef1c0ded9bec7f1a1670819833240f027b25eff"
|
|
34
|
+
[Dapp.ZEROEX]: "0xdef1c0ded9bec7f1a1670819833240f027b25eff",
|
|
35
|
+
[Dapp.ODOS]: "0x4e3288c9ca110bcc82bf38f09a7b425c095d92bf"
|
|
35
36
|
},
|
|
36
37
|
[Network.OPTIMISM]: {
|
|
37
38
|
[Dapp.UNISWAPV3]: "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45",
|
|
@@ -43,7 +44,8 @@ export const routerAddress: AddressDappNetworkMap = {
|
|
|
43
44
|
[Dapp.VELODROMEV2]: "0xa062ae8a9c5e11aaa026fc2670b0d65ccc8b2858",
|
|
44
45
|
[Dapp.LYRA]: "0xCCE7819d65f348c64B7Beb205BA367b3fE33763B",
|
|
45
46
|
[Dapp.ARRAKIS]: "0x9ce88a56d120300061593eF7AD074A1B710094d5",
|
|
46
|
-
[Dapp.ZEROEX]: "0xdef1abe32c034e558cdd535791643c58a13acc10"
|
|
47
|
+
[Dapp.ZEROEX]: "0xdef1abe32c034e558cdd535791643c58a13acc10",
|
|
48
|
+
[Dapp.ODOS]: "0xca423977156bb05b13a2ba3b76bc5419e2fe9680"
|
|
47
49
|
},
|
|
48
50
|
[Network.ARBITRUM]: {
|
|
49
51
|
[Dapp.ONEINCH]: "0x111111125421ca6dc452d289314280a0f8842a65",
|
|
@@ -52,14 +54,16 @@ export const routerAddress: AddressDappNetworkMap = {
|
|
|
52
54
|
[Dapp.BALANCER]: "0xBA12222222228d8Ba445958a75a0704d566BF2C8",
|
|
53
55
|
[Dapp.RAMSES]: "0xaaa87963efeb6f7e0a2711f397663105acb1805e",
|
|
54
56
|
[Dapp.ZEROEX]: "0xdef1c0ded9bec7f1a1670819833240f027b25eff",
|
|
55
|
-
[Dapp.TOROS]: "0xA5679C4272A056Bb83f039961fae7D99C48529F5"
|
|
57
|
+
[Dapp.TOROS]: "0xA5679C4272A056Bb83f039961fae7D99C48529F5",
|
|
58
|
+
[Dapp.ODOS]: "0xa669e7A0d4b3e4Fa48af2dE86BD4CD7126Be4e13"
|
|
56
59
|
},
|
|
57
60
|
[Network.BASE]: {
|
|
58
61
|
[Dapp.ONEINCH]: "0x111111125421ca6dc452d289314280a0f8842a65",
|
|
59
62
|
[Dapp.ZEROEX]: "0xdef1c0ded9bec7f1a1670819833240f027b25eff",
|
|
60
63
|
[Dapp.AERODROME]: "0xcF77a3Ba9A5CA399B7c97c74d54e5b1Beb874E43",
|
|
61
64
|
[Dapp.AAVEV3]: "0xA238Dd80C259a72e81d7e4664a9801593F98d1c5",
|
|
62
|
-
[Dapp.TOROS]: "0xf067575Eb60c7587C11e867907AA7284833704d1"
|
|
65
|
+
[Dapp.TOROS]: "0xf067575Eb60c7587C11e867907AA7284833704d1",
|
|
66
|
+
[Dapp.ODOS]: "0x19cEeAd7105607Cd444F5ad10dd51356436095a1"
|
|
63
67
|
}
|
|
64
68
|
};
|
|
65
69
|
|
|
@@ -166,10 +170,11 @@ export const flatMoneyContractAddresses: Readonly<Partial<
|
|
|
166
170
|
Record<
|
|
167
171
|
Network,
|
|
168
172
|
{
|
|
173
|
+
OrderExecution?: string;
|
|
169
174
|
DelayedOrder: string;
|
|
170
175
|
FlatcoinVault: string;
|
|
171
176
|
StableModule: string;
|
|
172
|
-
|
|
177
|
+
COLLATERAL: string;
|
|
173
178
|
}
|
|
174
179
|
>
|
|
175
180
|
>> = {
|
|
@@ -177,6 +182,13 @@ export const flatMoneyContractAddresses: Readonly<Partial<
|
|
|
177
182
|
DelayedOrder: "0x6D857e9D24a7566bB72a3FB0847A3E0e4E1c2879",
|
|
178
183
|
FlatcoinVault: "0x95Fa1ddc9a78273f795e67AbE8f1Cd2Cd39831fF",
|
|
179
184
|
StableModule: "0xb95fB324b8A2fAF8ec4f76e3dF46C718402736e2",
|
|
180
|
-
|
|
185
|
+
COLLATERAL: "0xb6fe221fe9eef5aba221c348ba20a1bf5e73624c" // RETH
|
|
186
|
+
},
|
|
187
|
+
[Network.OPTIMISM]: {
|
|
188
|
+
OrderExecution: "0x7805CB7fb2C2e70FDdF92949065D9Ee1Fc2F72a8",
|
|
189
|
+
DelayedOrder: "0xd917A0C9B21Bb71DF1209d2c211Ad83004F01554", // OrderAnnouncementModule
|
|
190
|
+
FlatcoinVault: "0x86C7b9640302082B0dF78023F930d8612bFcaD3f",
|
|
191
|
+
COLLATERAL: "0x68f180fcCe6836688e9084f035309E29Bf0A2095", // WBTC
|
|
192
|
+
StableModule: "0x357CB23571EF7a3d6189b7FAcFC361eA71f7CAB5"
|
|
181
193
|
}
|
|
182
194
|
};
|
package/src/entities/dhedge.ts
CHANGED
|
@@ -23,7 +23,6 @@ export class Dhedge {
|
|
|
23
23
|
PoolFactory.abi,
|
|
24
24
|
this.signer
|
|
25
25
|
);
|
|
26
|
-
|
|
27
26
|
this.utils = new Utils(this.network, this.signer);
|
|
28
27
|
}
|
|
29
28
|
|
|
@@ -87,9 +86,10 @@ export class Dhedge {
|
|
|
87
86
|
* @param {string} address Pool address
|
|
88
87
|
* @returns {Pool} Loaded Pool
|
|
89
88
|
*/
|
|
90
|
-
public async loadPool(address: string): Promise<Pool> {
|
|
89
|
+
public async loadPool(address: string, isDhedge = true): Promise<Pool> {
|
|
91
90
|
const poolLogic = new Contract(address, PoolLogic.abi, this.signer);
|
|
92
|
-
|
|
91
|
+
let managerLogicAddress = address;
|
|
92
|
+
if (isDhedge) managerLogicAddress = await poolLogic.poolManagerLogic();
|
|
93
93
|
const managerLogic = new Contract(
|
|
94
94
|
managerLogicAddress,
|
|
95
95
|
ManagerLogic.abi,
|
|
@@ -102,7 +102,8 @@ export class Dhedge {
|
|
|
102
102
|
poolLogic,
|
|
103
103
|
managerLogic,
|
|
104
104
|
this.utils,
|
|
105
|
-
this.factory
|
|
105
|
+
this.factory,
|
|
106
|
+
isDhedge
|
|
106
107
|
);
|
|
107
108
|
}
|
|
108
109
|
|
package/src/entities/pool.ts
CHANGED
|
@@ -86,6 +86,7 @@ import {
|
|
|
86
86
|
getPancakeStakeTxData,
|
|
87
87
|
getPancakeUnStakeTxData
|
|
88
88
|
} from "../services/pancake/staking";
|
|
89
|
+
import { getOdosSwapTxData } from "../services/odos";
|
|
89
90
|
|
|
90
91
|
export class Pool {
|
|
91
92
|
public readonly poolLogic: Contract;
|
|
@@ -95,6 +96,7 @@ export class Pool {
|
|
|
95
96
|
public readonly address: string;
|
|
96
97
|
public readonly utils: Utils;
|
|
97
98
|
public readonly network: Network;
|
|
99
|
+
public readonly isDhedge: boolean;
|
|
98
100
|
|
|
99
101
|
public constructor(
|
|
100
102
|
network: Network,
|
|
@@ -102,7 +104,8 @@ export class Pool {
|
|
|
102
104
|
poolLogic: Contract,
|
|
103
105
|
mangerLogic: Contract,
|
|
104
106
|
utils: Utils,
|
|
105
|
-
factory: Contract
|
|
107
|
+
factory: Contract,
|
|
108
|
+
isDhedge = true
|
|
106
109
|
) {
|
|
107
110
|
this.network = network;
|
|
108
111
|
this.poolLogic = poolLogic;
|
|
@@ -111,6 +114,7 @@ export class Pool {
|
|
|
111
114
|
this.signer = signer;
|
|
112
115
|
this.utils = utils;
|
|
113
116
|
this.factory = factory;
|
|
117
|
+
this.isDhedge = isDhedge;
|
|
114
118
|
}
|
|
115
119
|
|
|
116
120
|
/**
|
|
@@ -420,6 +424,15 @@ export class Pool {
|
|
|
420
424
|
slippage
|
|
421
425
|
);
|
|
422
426
|
break;
|
|
427
|
+
case Dapp.ODOS:
|
|
428
|
+
swapTxData = await getOdosSwapTxData(
|
|
429
|
+
this,
|
|
430
|
+
assetFrom,
|
|
431
|
+
assetTo,
|
|
432
|
+
amountIn,
|
|
433
|
+
slippage
|
|
434
|
+
);
|
|
435
|
+
break;
|
|
423
436
|
default:
|
|
424
437
|
const iUniswapV2Router = new ethers.utils.Interface(
|
|
425
438
|
IUniswapV2Router.abi
|
|
@@ -4,6 +4,7 @@ import IFlatcoinVaultAbi from "../../abi/flatmoney/IFlatcoinVault.json";
|
|
|
4
4
|
import KeeperFeeAbi from "../../abi/flatmoney/KeeperFee.json";
|
|
5
5
|
import { flatMoneyContractAddresses } from "../../config";
|
|
6
6
|
import BigNumber from "bignumber.js";
|
|
7
|
+
import { JsonRpcProvider } from "@ethersproject/providers";
|
|
7
8
|
|
|
8
9
|
export const getKeeperFeeContract = async (pool: Pool): Promise<Contract> => {
|
|
9
10
|
const flatMoneyContracts = flatMoneyContractAddresses[pool.network];
|
|
@@ -35,12 +36,16 @@ export const getKeeperFee = async (
|
|
|
35
36
|
maxKeeperFeeInUsd: number | null
|
|
36
37
|
): Promise<ethers.BigNumber> => {
|
|
37
38
|
const keeperFeeContract = await getKeeperFeeContract(pool);
|
|
38
|
-
|
|
39
|
+
|
|
40
|
+
const feeHistory = await (pool.signer
|
|
41
|
+
.provider as JsonRpcProvider).send("eth_feeHistory", [1, "latest"]);
|
|
42
|
+
|
|
43
|
+
const gasPrice = Number(feeHistory.baseFeePerGas[0]);
|
|
39
44
|
|
|
40
45
|
let keeperfee: ethers.BigNumber;
|
|
41
46
|
if (gasPrice) {
|
|
42
47
|
keeperfee = await keeperFeeContract["getKeeperFee(uint256)"](
|
|
43
|
-
new BigNumber(gasPrice.toString()).times(1.
|
|
48
|
+
new BigNumber(gasPrice.toString()).times(1.5).toFixed(0)
|
|
44
49
|
);
|
|
45
50
|
} else {
|
|
46
51
|
keeperfee = await keeperFeeContract["getKeeperFee()"]();
|
|
@@ -72,7 +77,7 @@ export const getKeeperFeeInUsd = async (
|
|
|
72
77
|
const filteredFc = fundComposition.filter(
|
|
73
78
|
fc =>
|
|
74
79
|
fc.asset.toLocaleLowerCase() ===
|
|
75
|
-
flatMoneyContracts.
|
|
80
|
+
flatMoneyContracts.COLLATERAL.toLocaleLowerCase()
|
|
76
81
|
);
|
|
77
82
|
|
|
78
83
|
if (!filteredFc[0])
|
|
@@ -80,5 +85,8 @@ export const getKeeperFeeInUsd = async (
|
|
|
80
85
|
|
|
81
86
|
const rateD1 = new BigNumber(filteredFc[0].rate.toString()).div(1e18);
|
|
82
87
|
|
|
83
|
-
|
|
88
|
+
const assetDecimal = await pool.utils.getDecimals(
|
|
89
|
+
flatMoneyContracts.COLLATERAL
|
|
90
|
+
);
|
|
91
|
+
return rateD1.times(keeperFee.toString()).div(10 ** assetDecimal);
|
|
84
92
|
};
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import BigNumber from "bignumber.js";
|
|
4
4
|
import { Pool, ethers } from "../..";
|
|
5
5
|
import DelayedOrderAbi from "../../abi/flatmoney/DelayedOrder.json";
|
|
6
|
+
import IOrderExecutionModuleAbi from "../../abi/flatmoney/v2/IOrderExecutionModule.json";
|
|
6
7
|
import { flatMoneyContractAddresses } from "../../config";
|
|
7
8
|
import { getPoolTxOrGasEstimate } from "../../utils/contract";
|
|
8
9
|
import { getStableDepositQuote, getStableWithdrawQuote } from "./stableModule";
|
|
@@ -42,6 +43,12 @@ export function getCancelExistingOrderTxData(account: string): string {
|
|
|
42
43
|
).encodeFunctionData("cancelExistingOrder", [account]);
|
|
43
44
|
}
|
|
44
45
|
|
|
46
|
+
export function getCancelExistingOrderTxDataForV2(account: string): string {
|
|
47
|
+
return new ethers.utils.Interface(
|
|
48
|
+
IOrderExecutionModuleAbi
|
|
49
|
+
).encodeFunctionData("cancelExistingOrder", [account]);
|
|
50
|
+
}
|
|
51
|
+
|
|
45
52
|
export async function mintUnitViaFlatMoney(
|
|
46
53
|
pool: Pool,
|
|
47
54
|
depositAmount: ethers.BigNumber | string,
|
|
@@ -55,7 +62,7 @@ export async function mintUnitViaFlatMoney(
|
|
|
55
62
|
throw new Error("mintUnitViaFlatMoney: network not supported");
|
|
56
63
|
}
|
|
57
64
|
|
|
58
|
-
const keeperfee = await getKeeperFee(pool, maxKeeperFeeInUsd); // in
|
|
65
|
+
const keeperfee = await getKeeperFee(pool, maxKeeperFeeInUsd); // in COLLATERAL
|
|
59
66
|
|
|
60
67
|
const adjustedDepositAmount = new BigNumber(depositAmount.toString()).minus(
|
|
61
68
|
keeperfee.toString() // keeper fee deducted from amountIn
|
|
@@ -125,11 +132,26 @@ export async function cancelOrderViaFlatMoney(
|
|
|
125
132
|
if (!flatMoneyContracts) {
|
|
126
133
|
throw new Error("cancelOrderViaFlatMoney: network not supported");
|
|
127
134
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
+
// flat money v2
|
|
136
|
+
// use OrderExecution module to cancel order
|
|
137
|
+
let toAddress = flatMoneyContracts.DelayedOrder;
|
|
138
|
+
let cancelOrderTxData = getCancelExistingOrderTxData(pool.address);
|
|
139
|
+
if (flatMoneyContracts.OrderExecution) {
|
|
140
|
+
toAddress = flatMoneyContracts.OrderExecution;
|
|
141
|
+
cancelOrderTxData = await getCancelExistingOrderTxDataForV2(pool.address);
|
|
142
|
+
}
|
|
143
|
+
// use trader address to cancel order
|
|
144
|
+
if (estimateGas) {
|
|
145
|
+
return pool.signer.estimateGas({
|
|
146
|
+
to: toAddress,
|
|
147
|
+
data: cancelOrderTxData
|
|
148
|
+
});
|
|
149
|
+
} else {
|
|
150
|
+
const tx = await pool.signer.sendTransaction({
|
|
151
|
+
to: toAddress,
|
|
152
|
+
data: cancelOrderTxData,
|
|
153
|
+
...options
|
|
154
|
+
});
|
|
155
|
+
return tx;
|
|
156
|
+
}
|
|
135
157
|
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import axios from "axios";
|
|
3
|
+
import { ApiError, ethers } from "../..";
|
|
4
|
+
import { networkChainIdMap } from "../../config";
|
|
5
|
+
import { Pool } from "../../entities";
|
|
6
|
+
|
|
7
|
+
const odosBaseUrl = "https://api.odos.xyz/sor";
|
|
8
|
+
|
|
9
|
+
export async function getOdosSwapTxData(
|
|
10
|
+
pool: Pool,
|
|
11
|
+
assetFrom: string,
|
|
12
|
+
assetTo: string,
|
|
13
|
+
amountIn: ethers.BigNumber | string,
|
|
14
|
+
slippage: number
|
|
15
|
+
): Promise<string> {
|
|
16
|
+
let referralCode = 0; // Defaults to 0 for unregistered activity.
|
|
17
|
+
if (
|
|
18
|
+
process.env.ODOS_REFERAL_CODE &&
|
|
19
|
+
Number(process.env.ODOS_REFERAL_CODE) > 0
|
|
20
|
+
) {
|
|
21
|
+
referralCode = Number(process.env.ODOS_REFERAL_CODE);
|
|
22
|
+
}
|
|
23
|
+
const quoteParams = {
|
|
24
|
+
chainId: networkChainIdMap[pool.network],
|
|
25
|
+
inputTokens: [
|
|
26
|
+
{
|
|
27
|
+
tokenAddress: assetFrom,
|
|
28
|
+
amount: amountIn.toString()
|
|
29
|
+
}
|
|
30
|
+
],
|
|
31
|
+
outputTokens: [
|
|
32
|
+
{
|
|
33
|
+
tokenAddress: assetTo,
|
|
34
|
+
proportion: 1
|
|
35
|
+
}
|
|
36
|
+
],
|
|
37
|
+
slippageLimitPercent: slippage,
|
|
38
|
+
userAddr: pool.address,
|
|
39
|
+
referralCode
|
|
40
|
+
};
|
|
41
|
+
try {
|
|
42
|
+
const quoteResult = await axios.post(
|
|
43
|
+
`${odosBaseUrl}/quote/v2`,
|
|
44
|
+
quoteParams
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
const assembleParams = {
|
|
48
|
+
pathId: quoteResult.data.pathId,
|
|
49
|
+
userAddr: pool.address
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const assembleResult = await axios.post(
|
|
53
|
+
`${odosBaseUrl}/assemble`,
|
|
54
|
+
assembleParams
|
|
55
|
+
);
|
|
56
|
+
return assembleResult.data.transaction.data;
|
|
57
|
+
} catch (e) {
|
|
58
|
+
console.error("Error in Odos API request:", e);
|
|
59
|
+
throw new ApiError("Swap api request of Odos failed");
|
|
60
|
+
}
|
|
61
|
+
}
|
package/src/test/constants.ts
CHANGED
|
@@ -62,7 +62,8 @@ export const CONTRACT_ADDRESS = {
|
|
|
62
62
|
VELODROME_CL_USDC_WETH_GAUGE: "",
|
|
63
63
|
VELO: "",
|
|
64
64
|
COMPOUNDV3_WETH: "",
|
|
65
|
-
TOROS: ""
|
|
65
|
+
TOROS: "",
|
|
66
|
+
UNIT: ""
|
|
66
67
|
},
|
|
67
68
|
|
|
68
69
|
[Network.OPTIMISM]: {
|
|
@@ -77,6 +78,7 @@ export const CONTRACT_ADDRESS = {
|
|
|
77
78
|
nonfungiblePositionManager: "0xC36442b4a4522E871399CD717aBDD847Ab11FE88"
|
|
78
79
|
},
|
|
79
80
|
|
|
81
|
+
UNIT: "0x357CB23571EF7a3d6189b7FAcFC361eA71f7CAB5",
|
|
80
82
|
WMATIC: "",
|
|
81
83
|
//
|
|
82
84
|
ARRAKIS_USDC_WETH_GAUGE: "",
|
|
@@ -101,6 +103,8 @@ export const CONTRACT_ADDRESS = {
|
|
|
101
103
|
nonfungiblePositionManager: "0xC36442b4a4522E871399CD717aBDD847Ab11FE88"
|
|
102
104
|
},
|
|
103
105
|
|
|
106
|
+
UNIT: "",
|
|
107
|
+
|
|
104
108
|
//
|
|
105
109
|
ARRAKIS_USDC_WETH_GAUGE: "",
|
|
106
110
|
ARRAKIS_USDC_WETH_LP: "",
|
|
@@ -117,6 +121,7 @@ export const CONTRACT_ADDRESS = {
|
|
|
117
121
|
WETH: "0x4200000000000000000000000000000000000006",
|
|
118
122
|
WBTC: "",
|
|
119
123
|
SWETH: "",
|
|
124
|
+
UNIT: "0xb95fB324b8A2fAF8ec4f76e3dF46C718402736e2",
|
|
120
125
|
uniswapV3: {
|
|
121
126
|
nonfungiblePositionManager: ""
|
|
122
127
|
},
|
|
@@ -4,6 +4,7 @@ import { Dhedge, Pool } from "../entities";
|
|
|
4
4
|
import { AssetEnabled, Network } from "../types";
|
|
5
5
|
import {
|
|
6
6
|
TestingRunParams,
|
|
7
|
+
runWithImpersonateAccount,
|
|
7
8
|
setTokenAmount,
|
|
8
9
|
testingHelper
|
|
9
10
|
} from "./utils/testingHelper";
|
|
@@ -14,9 +15,7 @@ import DelayedOrderAbi from "../abi/flatmoney/DelayedOrder.json";
|
|
|
14
15
|
import { allowanceDelta } from "./utils/token";
|
|
15
16
|
import { getKeeperFee } from "../services/flatmoney/keeperFee";
|
|
16
17
|
|
|
17
|
-
const
|
|
18
|
-
const RETH_SLOT = 0;
|
|
19
|
-
const UNIT = "0xb95fB324b8A2fAF8ec4f76e3dF46C718402736e2";
|
|
18
|
+
const COLLATERAL_SLOT = 0; // same for RETH(base) and WBTC(optimism)
|
|
20
19
|
// https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/master/contracts/token/ERC20/ERC20Upgradeable.sol#L31
|
|
21
20
|
// https://eips.ethereum.org/EIPS/eip-7201
|
|
22
21
|
const UNIT_SLOT =
|
|
@@ -31,16 +30,26 @@ const testFlatMoney = ({
|
|
|
31
30
|
let dhedge: Dhedge;
|
|
32
31
|
let pool: Pool;
|
|
33
32
|
let delayOrderContract: Contract;
|
|
33
|
+
let COLLATERAL: string;
|
|
34
34
|
jest.setTimeout(200000);
|
|
35
35
|
describe(`flatmoney on ${network}`, () => {
|
|
36
36
|
beforeAll(async () => {
|
|
37
|
+
await provider.send("evm_mine", []);
|
|
37
38
|
dhedge = new Dhedge(wallet, network);
|
|
38
39
|
pool = await dhedge.loadPool(TEST_POOL[network]);
|
|
39
40
|
|
|
41
|
+
await runWithImpersonateAccount(
|
|
42
|
+
{ provider, account: await pool.managerLogic.manager() },
|
|
43
|
+
async ({ signer }) => {
|
|
44
|
+
await pool.managerLogic.connect(signer).setTrader(wallet.address);
|
|
45
|
+
}
|
|
46
|
+
);
|
|
47
|
+
|
|
40
48
|
const flatMoneyContracts = flatMoneyContractAddresses[pool.network];
|
|
41
49
|
if (!flatMoneyContracts) {
|
|
42
50
|
throw new Error("testFlatMoney: network not supported");
|
|
43
51
|
}
|
|
52
|
+
COLLATERAL = flatMoneyContracts.COLLATERAL;
|
|
44
53
|
delayOrderContract = new Contract(
|
|
45
54
|
flatMoneyContracts.DelayedOrder,
|
|
46
55
|
DelayedOrderAbi,
|
|
@@ -57,14 +66,14 @@ const testFlatMoney = ({
|
|
|
57
66
|
await setTokenAmount({
|
|
58
67
|
amount: new BigNumber(100).times(1e18).toString(),
|
|
59
68
|
provider,
|
|
60
|
-
tokenAddress:
|
|
61
|
-
slot:
|
|
69
|
+
tokenAddress: COLLATERAL,
|
|
70
|
+
slot: COLLATERAL_SLOT,
|
|
62
71
|
userAddress: pool.address
|
|
63
72
|
});
|
|
64
73
|
await setTokenAmount({
|
|
65
74
|
amount: new BigNumber(100).times(1e18).toString(),
|
|
66
75
|
provider,
|
|
67
|
-
tokenAddress: UNIT,
|
|
76
|
+
tokenAddress: CONTRACT_ADDRESS[network].UNIT,
|
|
68
77
|
slot: UNIT_SLOT,
|
|
69
78
|
userAddress: pool.address
|
|
70
79
|
});
|
|
@@ -82,11 +91,11 @@ const testFlatMoney = ({
|
|
|
82
91
|
{ asset: CONTRACT_ADDRESS[network].USDC, isDeposit: true },
|
|
83
92
|
{ asset: CONTRACT_ADDRESS[network].WETH, isDeposit: true },
|
|
84
93
|
{
|
|
85
|
-
asset: UNIT,
|
|
94
|
+
asset: CONTRACT_ADDRESS[network].UNIT,
|
|
86
95
|
isDeposit: false
|
|
87
96
|
},
|
|
88
97
|
{
|
|
89
|
-
asset:
|
|
98
|
+
asset: COLLATERAL,
|
|
90
99
|
isDeposit: false
|
|
91
100
|
}
|
|
92
101
|
];
|
|
@@ -95,10 +104,14 @@ const testFlatMoney = ({
|
|
|
95
104
|
|
|
96
105
|
it("mint UNIT", async () => {
|
|
97
106
|
//approve
|
|
98
|
-
await pool.approveSpender(
|
|
107
|
+
await pool.approveSpender(
|
|
108
|
+
delayOrderContract.address,
|
|
109
|
+
COLLATERAL,
|
|
110
|
+
MAX_AMOUNT
|
|
111
|
+
);
|
|
99
112
|
const collateralAllowanceDelta = await allowanceDelta(
|
|
100
113
|
pool.address,
|
|
101
|
-
|
|
114
|
+
COLLATERAL,
|
|
102
115
|
delayOrderContract.address,
|
|
103
116
|
pool.signer
|
|
104
117
|
);
|
|
@@ -129,7 +142,13 @@ const testFlatMoney = ({
|
|
|
129
142
|
});
|
|
130
143
|
|
|
131
144
|
it("redeem UNIT", async () => {
|
|
132
|
-
|
|
145
|
+
let withdrawAmountStr;
|
|
146
|
+
if (Network.OPTIMISM === network) {
|
|
147
|
+
withdrawAmountStr = new BigNumber(2).times(1e8).toString(); // smaller amount
|
|
148
|
+
} else {
|
|
149
|
+
withdrawAmountStr = new BigNumber(2).times(1e18).toString();
|
|
150
|
+
}
|
|
151
|
+
|
|
133
152
|
const tx = await pool.redeemUnitViaFlatMoney(
|
|
134
153
|
withdrawAmountStr,
|
|
135
154
|
0.5,
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
2
|
+
|
|
3
|
+
import { Dhedge, Pool } from "..";
|
|
4
|
+
|
|
5
|
+
import { Dapp, Network } from "../types";
|
|
6
|
+
import { CONTRACT_ADDRESS, MAX_AMOUNT, TEST_POOL } from "./constants";
|
|
7
|
+
import {
|
|
8
|
+
TestingRunParams,
|
|
9
|
+
setUSDCAmount,
|
|
10
|
+
testingHelper,
|
|
11
|
+
wait
|
|
12
|
+
} from "./utils/testingHelper";
|
|
13
|
+
import { allowanceDelta, balanceDelta } from "./utils/token";
|
|
14
|
+
import { getTxOptions } from "./txOptions";
|
|
15
|
+
import BigNumber from "bignumber.js";
|
|
16
|
+
import { routerAddress } from "../config";
|
|
17
|
+
|
|
18
|
+
const testOdos = ({ wallet, network, provider }: TestingRunParams) => {
|
|
19
|
+
const USDC = CONTRACT_ADDRESS[network].USDC;
|
|
20
|
+
const WETH = CONTRACT_ADDRESS[network].WETH;
|
|
21
|
+
|
|
22
|
+
let dhedge: Dhedge;
|
|
23
|
+
let pool: Pool;
|
|
24
|
+
jest.setTimeout(100000);
|
|
25
|
+
|
|
26
|
+
describe(`pool on ${network}`, () => {
|
|
27
|
+
beforeAll(async () => {
|
|
28
|
+
dhedge = new Dhedge(wallet, network);
|
|
29
|
+
pool = await dhedge.loadPool(TEST_POOL[network]);
|
|
30
|
+
// top up gas
|
|
31
|
+
await provider.send("hardhat_setBalance", [
|
|
32
|
+
wallet.address,
|
|
33
|
+
"0x10000000000000000"
|
|
34
|
+
]);
|
|
35
|
+
await provider.send("evm_mine", []);
|
|
36
|
+
// top up USDC
|
|
37
|
+
await setUSDCAmount({
|
|
38
|
+
amount: new BigNumber(2).times(1e6).toFixed(0),
|
|
39
|
+
userAddress: pool.address,
|
|
40
|
+
network,
|
|
41
|
+
provider
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("approves unlimited USDC on Odos", async () => {
|
|
46
|
+
await pool.approve(Dapp.ODOS, USDC, MAX_AMOUNT);
|
|
47
|
+
const usdcAllowanceDelta = await allowanceDelta(
|
|
48
|
+
pool.address,
|
|
49
|
+
USDC,
|
|
50
|
+
routerAddress[network]["odos"]!,
|
|
51
|
+
pool.signer
|
|
52
|
+
);
|
|
53
|
+
await expect(usdcAllowanceDelta.gt(0));
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("gets gas estimation for 2 USDC into WETH on Odos", async () => {
|
|
57
|
+
const gasEstimate = await pool.trade(
|
|
58
|
+
Dapp.ODOS,
|
|
59
|
+
USDC,
|
|
60
|
+
WETH,
|
|
61
|
+
"2000000",
|
|
62
|
+
1,
|
|
63
|
+
await getTxOptions(network),
|
|
64
|
+
true
|
|
65
|
+
);
|
|
66
|
+
expect(gasEstimate.gt(0));
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("trades 2 USDC into WETH on Odos", async () => {
|
|
70
|
+
await wait(1);
|
|
71
|
+
await pool.trade(
|
|
72
|
+
Dapp.ODOS,
|
|
73
|
+
USDC,
|
|
74
|
+
WETH,
|
|
75
|
+
"2000000",
|
|
76
|
+
0.5,
|
|
77
|
+
await getTxOptions(network)
|
|
78
|
+
);
|
|
79
|
+
const wethBalanceDelta = await balanceDelta(
|
|
80
|
+
pool.address,
|
|
81
|
+
WETH,
|
|
82
|
+
pool.signer
|
|
83
|
+
);
|
|
84
|
+
expect(wethBalanceDelta.gt(0));
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
// testingHelper({
|
|
90
|
+
// network: Network.OPTIMISM,
|
|
91
|
+
// testingRun: testOdos
|
|
92
|
+
// });
|
|
93
|
+
|
|
94
|
+
testingHelper({
|
|
95
|
+
network: Network.ARBITRUM,
|
|
96
|
+
testingRun: testOdos
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// testingHelper({
|
|
100
|
+
// network: Network.POLYGON,
|
|
101
|
+
// onFork: false,
|
|
102
|
+
// testingRun: testOdos
|
|
103
|
+
// });
|
|
104
|
+
|
|
105
|
+
// testingHelper({
|
|
106
|
+
// network: Network.BASE,
|
|
107
|
+
// onFork: false,
|
|
108
|
+
// testingRun: testOdos
|
|
109
|
+
// });
|