@dhedge/v2-sdk 2.2.0 → 2.2.2
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/README.md +4 -1
- package/dist/config.d.ts +3 -0
- package/dist/entities/pool.d.ts +3 -1
- package/dist/services/dytm/index.d.ts +7 -0
- package/dist/services/ondo/index.d.ts +5 -0
- package/dist/services/toros/completeWithdrawal.d.ts +2 -2
- package/dist/services/toros/easySwapper.d.ts +4 -1
- package/dist/services/toros/initWithdrawal.d.ts +4 -1
- package/dist/types.d.ts +3 -1
- package/dist/v2-sdk.cjs.development.js +708 -119
- 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 +708 -119
- package/dist/v2-sdk.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/abi/dytm/IOffice.json +191 -0
- package/src/abi/ondo/IOndoGMSwap.json +30 -0
- package/src/config.ts +21 -2
- package/src/entities/pool.ts +76 -32
- package/src/services/dytm/index.ts +77 -0
- package/src/services/ondo/index.ts +142 -0
- package/src/services/toros/completeWithdrawal.ts +23 -7
- package/src/services/toros/easySwapper.ts +9 -7
- package/src/services/toros/initWithdrawal.ts +10 -6
- package/src/test/dytm.test.ts +241 -0
- package/src/test/ondo.onchain.test.ts +132 -0
- package/src/types.ts +3 -1
|
@@ -70,19 +70,23 @@ const getSwapWithdrawData = async (
|
|
|
70
70
|
}
|
|
71
71
|
throw new Error("All swap routers failed for complete withdrawal");
|
|
72
72
|
};
|
|
73
|
+
|
|
73
74
|
export const createCompleteWithdrawalTxArguments = async (
|
|
74
75
|
pool: Pool,
|
|
75
76
|
receiveToken: string,
|
|
76
|
-
slippage: number
|
|
77
|
+
slippage: number,
|
|
78
|
+
_trackedAssets: TrackedAsset[]
|
|
77
79
|
): Promise<any> => {
|
|
78
80
|
const easySwapper = new ethers.Contract(
|
|
79
81
|
routerAddress[pool.network][Dapp.TOROS] as string,
|
|
80
82
|
IEasySwapperV2,
|
|
81
83
|
pool.signer
|
|
82
84
|
);
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
)
|
|
85
|
+
|
|
86
|
+
let trackedAssets: TrackedAsset[] = _trackedAssets;
|
|
87
|
+
if (trackedAssets.length === 0) {
|
|
88
|
+
trackedAssets = await easySwapper.getTrackedAssets(pool.address);
|
|
89
|
+
}
|
|
86
90
|
|
|
87
91
|
if (
|
|
88
92
|
trackedAssets.length === 0 ||
|
|
@@ -170,10 +174,20 @@ export const createCompleteWithdrawalTxArguments = async (
|
|
|
170
174
|
const withdrawalVaultAddress = await easySwapper.withdrawalContracts(
|
|
171
175
|
pool.address
|
|
172
176
|
);
|
|
173
|
-
|
|
177
|
+
let balanceOfReceiveToken = await receiveTokenErc20.balanceOf(
|
|
174
178
|
withdrawalVaultAddress
|
|
175
179
|
);
|
|
176
180
|
|
|
181
|
+
if (trackedAssets.length !== 0) {
|
|
182
|
+
// finds the receiveTokenErc20's balance inside trackedAssets
|
|
183
|
+
const trackedAsset = trackedAssets.find(
|
|
184
|
+
({ token }) => token.toLowerCase() === receiveToken.toLowerCase()
|
|
185
|
+
);
|
|
186
|
+
if (trackedAsset) {
|
|
187
|
+
balanceOfReceiveToken = balanceOfReceiveToken.add(trackedAsset.balance);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
177
191
|
// complete withdraw _expectedDestTokenAmount
|
|
178
192
|
const estimatedMinReceiveAmount = swapDestMinDestAmount.plus(
|
|
179
193
|
balanceOfReceiveToken.toString()
|
|
@@ -201,12 +215,14 @@ export const getCompleteWithdrawalTxData = async (
|
|
|
201
215
|
pool: Pool,
|
|
202
216
|
receiveToken: string,
|
|
203
217
|
slippage: number,
|
|
204
|
-
useOnChainSwap: boolean
|
|
218
|
+
useOnChainSwap: boolean,
|
|
219
|
+
trackedAssets: TrackedAsset[]
|
|
205
220
|
): Promise<string> => {
|
|
206
221
|
const completeWithdrawTxArguments = await createCompleteWithdrawalTxArguments(
|
|
207
222
|
pool,
|
|
208
223
|
receiveToken,
|
|
209
|
-
slippage
|
|
224
|
+
slippage,
|
|
225
|
+
trackedAssets
|
|
210
226
|
);
|
|
211
227
|
|
|
212
228
|
const isSwapNeeded = completeWithdrawTxArguments.isSwapNeeded;
|
|
@@ -70,7 +70,7 @@ export async function getEasySwapperTxData(
|
|
|
70
70
|
amountIn: ethers.BigNumber,
|
|
71
71
|
slippage: number
|
|
72
72
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
73
|
-
): Promise<any> {
|
|
73
|
+
): Promise<{ swapTxData: string; minAmountOut?: any }> {
|
|
74
74
|
const isWithdrawal = await isPool(pool, assetFrom);
|
|
75
75
|
const [torosAsset, investAsset] = isWithdrawal
|
|
76
76
|
? [assetFrom, assetTo]
|
|
@@ -99,11 +99,13 @@ export async function getEasySwapperTxData(
|
|
|
99
99
|
investAsset,
|
|
100
100
|
amountIn
|
|
101
101
|
);
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
102
|
+
const _minAmountOut = minAmountOut.mul(10000 - slippage * 100).div(10000);
|
|
103
|
+
return {
|
|
104
|
+
swapTxData: iEasySwapperV2.encodeFunctionData(
|
|
105
|
+
"depositWithCustomCooldown",
|
|
106
|
+
[torosAsset, depositAsset, amountIn, _minAmountOut]
|
|
107
|
+
),
|
|
108
|
+
minAmountOut: _minAmountOut
|
|
109
|
+
};
|
|
108
110
|
}
|
|
109
111
|
}
|
|
@@ -157,7 +157,7 @@ export const getInitWithdrawalTxData = async (
|
|
|
157
157
|
amountIn: string,
|
|
158
158
|
slippage: number,
|
|
159
159
|
useOnChainSwap: boolean
|
|
160
|
-
): Promise<string> => {
|
|
160
|
+
): Promise<{ swapTxData: string; minAmountOut?: any }> => {
|
|
161
161
|
const complexAssetsData = await createWithdrawTxArguments(
|
|
162
162
|
pool,
|
|
163
163
|
torosAsset,
|
|
@@ -166,9 +166,13 @@ export const getInitWithdrawalTxData = async (
|
|
|
166
166
|
useOnChainSwap
|
|
167
167
|
);
|
|
168
168
|
const iEasySwapperV2 = new ethers.utils.Interface(IEasySwapperV2);
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
169
|
+
|
|
170
|
+
return {
|
|
171
|
+
swapTxData: iEasySwapperV2.encodeFunctionData("initWithdrawal", [
|
|
172
|
+
torosAsset,
|
|
173
|
+
amountIn,
|
|
174
|
+
complexAssetsData
|
|
175
|
+
]),
|
|
176
|
+
minAmountOut: null // not be used when building multicall tx data
|
|
177
|
+
};
|
|
174
178
|
};
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
2
|
+
|
|
3
|
+
import BigNumber from "bignumber.js";
|
|
4
|
+
import { BigNumber as EthersBigNumber, Contract, providers } from "ethers";
|
|
5
|
+
import { Dhedge, Pool } from "..";
|
|
6
|
+
import { Dapp, Network } from "../types";
|
|
7
|
+
import { CONTRACT_ADDRESS, MAX_AMOUNT } from "./constants";
|
|
8
|
+
import {
|
|
9
|
+
TestingRunParams,
|
|
10
|
+
runWithImpersonateAccount,
|
|
11
|
+
setTokenAmount,
|
|
12
|
+
setUSDCAmount,
|
|
13
|
+
testingHelper
|
|
14
|
+
} from "./utils/testingHelper";
|
|
15
|
+
import { balanceDelta } from "./utils/token";
|
|
16
|
+
import { routerAddress } from "../config";
|
|
17
|
+
|
|
18
|
+
const officeAbi = [
|
|
19
|
+
"function getMarketConfig(uint88 market) view returns (address marketConfig)"
|
|
20
|
+
];
|
|
21
|
+
const marketConfigAbi = ["function hooks() view returns (address hooks)"];
|
|
22
|
+
const borrowerWhitelistAbi = [
|
|
23
|
+
"function owner() view returns (address)",
|
|
24
|
+
"function setAddressWhitelist(address accountOwner, bool allowed)"
|
|
25
|
+
];
|
|
26
|
+
const erc20AllowanceAbi = [
|
|
27
|
+
"function allowance(address owner, address spender) view returns (uint256)"
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
const DYTM_MARKET_ID = 1;
|
|
31
|
+
// ReserveKey: (marketId uint88 << 160) | asset address — DYTM src/types/ReserveKey.sol
|
|
32
|
+
const toReserveKey = (marketId: number, asset: string): EthersBigNumber =>
|
|
33
|
+
EthersBigNumber.from(marketId)
|
|
34
|
+
.shl(160)
|
|
35
|
+
.or(asset);
|
|
36
|
+
// full tokenId: (TokenType << 248) | reserveKey — DYTM src/libraries/TokenHelpers.sol
|
|
37
|
+
// TokenType: ESCROW = 1, LEND = 2, DEBT = 3
|
|
38
|
+
const toLentId = (key: EthersBigNumber): EthersBigNumber =>
|
|
39
|
+
EthersBigNumber.from(2)
|
|
40
|
+
.shl(248)
|
|
41
|
+
.or(key);
|
|
42
|
+
const toEscrowId = (key: EthersBigNumber): EthersBigNumber =>
|
|
43
|
+
EthersBigNumber.from(1)
|
|
44
|
+
.shl(248)
|
|
45
|
+
.or(key);
|
|
46
|
+
|
|
47
|
+
// SPYon (Ondo) collateral on mainnet market 1
|
|
48
|
+
const SPYON_MAINNET = "0xFeDC5f4a6c38211c1338aa411018DFAf26612c08";
|
|
49
|
+
const SPYON_BALANCEOF_SLOT = 51; // OZ ERC20Upgradeable layout
|
|
50
|
+
|
|
51
|
+
// market 1 borrows are gated by the BorrowerWhitelist hook — impersonate its
|
|
52
|
+
// owner and whitelist the pool
|
|
53
|
+
const whitelistPoolAsBorrower = async ({
|
|
54
|
+
pool,
|
|
55
|
+
network,
|
|
56
|
+
provider
|
|
57
|
+
}: {
|
|
58
|
+
pool: Pool;
|
|
59
|
+
network: Network;
|
|
60
|
+
provider: providers.JsonRpcProvider;
|
|
61
|
+
}): Promise<void> => {
|
|
62
|
+
const office = new Contract(
|
|
63
|
+
routerAddress[network][Dapp.DYTM]!,
|
|
64
|
+
officeAbi,
|
|
65
|
+
provider
|
|
66
|
+
);
|
|
67
|
+
const marketConfigAddress = await office.getMarketConfig(DYTM_MARKET_ID);
|
|
68
|
+
const hookAddress = await new Contract(
|
|
69
|
+
marketConfigAddress,
|
|
70
|
+
marketConfigAbi,
|
|
71
|
+
provider
|
|
72
|
+
).hooks();
|
|
73
|
+
const hook = new Contract(hookAddress, borrowerWhitelistAbi, provider);
|
|
74
|
+
const hookOwner = await hook.owner();
|
|
75
|
+
await runWithImpersonateAccount(
|
|
76
|
+
{ account: hookOwner, provider },
|
|
77
|
+
async ({ signer }) => {
|
|
78
|
+
await hook.connect(signer).setAddressWhitelist(pool.address, true);
|
|
79
|
+
}
|
|
80
|
+
);
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const testDytm = ({ network, wallet, provider }: TestingRunParams) => {
|
|
84
|
+
const USDC = CONTRACT_ADDRESS[network].USDC;
|
|
85
|
+
const usdcKey = toReserveKey(DYTM_MARKET_ID, USDC);
|
|
86
|
+
// supply/withdraw take the full LEND tokenId; borrow/repay take the bare ReserveKey
|
|
87
|
+
const USDC_DEPOSIT_TOKEN = toLentId(usdcKey).toString();
|
|
88
|
+
const USDC_BORROW_TOKEN = usdcKey.toString();
|
|
89
|
+
|
|
90
|
+
const USDC_FUNDING_AMOUNT = new BigNumber(100).shiftedBy(6).toFixed(0);
|
|
91
|
+
const USDC_LIQUIDITY_AMOUNT = new BigNumber(50).shiftedBy(6).toFixed(0);
|
|
92
|
+
|
|
93
|
+
// the asset backing the borrow differs per network: on arbitrum lent USDC
|
|
94
|
+
// counts as collateral, on mainnet USDC has lend weight 0 and SPYon escrow
|
|
95
|
+
// collateral (weight 0.75) is required instead
|
|
96
|
+
const collateral =
|
|
97
|
+
network === Network.ETHEREUM
|
|
98
|
+
? {
|
|
99
|
+
asset: SPYON_MAINNET,
|
|
100
|
+
tokenId: toEscrowId(
|
|
101
|
+
toReserveKey(DYTM_MARKET_ID, SPYON_MAINNET)
|
|
102
|
+
).toString(),
|
|
103
|
+
supplyAmount: new BigNumber(1).shiftedBy(18).toFixed(0),
|
|
104
|
+
// SPYon isn't covered by the USDC funding — deal it via its balanceOf slot
|
|
105
|
+
funding: {
|
|
106
|
+
slot: SPYON_BALANCEOF_SLOT,
|
|
107
|
+
amount: new BigNumber(10).shiftedBy(18).toFixed(0)
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
: {
|
|
111
|
+
asset: USDC,
|
|
112
|
+
tokenId: USDC_DEPOSIT_TOKEN,
|
|
113
|
+
supplyAmount: USDC_LIQUIDITY_AMOUNT,
|
|
114
|
+
funding: null // covered by the USDC funded in beforeAll
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
let dhedge: Dhedge;
|
|
118
|
+
let pool: Pool;
|
|
119
|
+
jest.setTimeout(100000);
|
|
120
|
+
|
|
121
|
+
describe(`[${network}] DYTM tests`, () => {
|
|
122
|
+
beforeAll(async () => {
|
|
123
|
+
// top up ETH (gas)
|
|
124
|
+
await provider.send("hardhat_setBalance", [
|
|
125
|
+
wallet.address,
|
|
126
|
+
"0x100000000000000"
|
|
127
|
+
]);
|
|
128
|
+
// mine a local block so eth_calls run under hardhat's own hardfork —
|
|
129
|
+
// the remote fork-point block executes as london (hardforkHistory) and
|
|
130
|
+
// lacks the cancun opcodes DYTM needs (transient storage)
|
|
131
|
+
await provider.send("evm_mine", []);
|
|
132
|
+
dhedge = new Dhedge(wallet, network);
|
|
133
|
+
pool = await dhedge.loadPool(wallet.address, false);
|
|
134
|
+
|
|
135
|
+
await whitelistPoolAsBorrower({ pool, network, provider });
|
|
136
|
+
|
|
137
|
+
// fund USDC and supply half of it as market liquidity to be borrowed
|
|
138
|
+
await setUSDCAmount({
|
|
139
|
+
amount: USDC_FUNDING_AMOUNT,
|
|
140
|
+
userAddress: pool.address,
|
|
141
|
+
network,
|
|
142
|
+
provider
|
|
143
|
+
});
|
|
144
|
+
await pool.approve(Dapp.DYTM, USDC, MAX_AMOUNT);
|
|
145
|
+
await pool.lend(Dapp.DYTM, USDC_DEPOSIT_TOKEN, USDC_LIQUIDITY_AMOUNT);
|
|
146
|
+
|
|
147
|
+
// fund the collateral asset for the supply tests
|
|
148
|
+
if (collateral.funding) {
|
|
149
|
+
await setTokenAmount({
|
|
150
|
+
amount: collateral.funding.amount,
|
|
151
|
+
userAddress: pool.address,
|
|
152
|
+
tokenAddress: collateral.asset,
|
|
153
|
+
slot: collateral.funding.slot,
|
|
154
|
+
provider
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it("approves unlimited collateral for DYTM", async () => {
|
|
160
|
+
await pool.approve(Dapp.DYTM, collateral.asset, MAX_AMOUNT);
|
|
161
|
+
const allowance = await new Contract(
|
|
162
|
+
collateral.asset,
|
|
163
|
+
erc20AllowanceAbi,
|
|
164
|
+
provider
|
|
165
|
+
).allowance(pool.address, routerAddress[network][Dapp.DYTM]!);
|
|
166
|
+
expect(allowance.eq(MAX_AMOUNT)).toBe(true);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it("estimates supplying collateral to DYTM market", async () => {
|
|
170
|
+
const result = await pool.lend(
|
|
171
|
+
Dapp.DYTM,
|
|
172
|
+
collateral.tokenId,
|
|
173
|
+
collateral.supplyAmount,
|
|
174
|
+
0,
|
|
175
|
+
null,
|
|
176
|
+
true
|
|
177
|
+
);
|
|
178
|
+
expect(result.gas.gt(0)).toBe(true);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it("supplies collateral to DYTM market", async () => {
|
|
182
|
+
await pool.lend(Dapp.DYTM, collateral.tokenId, collateral.supplyAmount);
|
|
183
|
+
|
|
184
|
+
const collateralDelta = await balanceDelta(
|
|
185
|
+
pool.address,
|
|
186
|
+
collateral.asset,
|
|
187
|
+
pool.signer
|
|
188
|
+
);
|
|
189
|
+
expect(collateralDelta.lt(0)).toBe(true);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it("borrows USDC from DYTM market", async () => {
|
|
193
|
+
// borrow value must clear the market's minDebtAmountUSD ($1 on arbitrum);
|
|
194
|
+
// borrow 3 USDC so the ~2 USDC debt left after the repay test stays above it
|
|
195
|
+
await pool.borrow(Dapp.DYTM, USDC_BORROW_TOKEN, (3 * 1e6).toString());
|
|
196
|
+
|
|
197
|
+
const usdcTokenDelta = await balanceDelta(
|
|
198
|
+
pool.address,
|
|
199
|
+
USDC,
|
|
200
|
+
pool.signer
|
|
201
|
+
);
|
|
202
|
+
expect(usdcTokenDelta.gt(0)).toBe(true);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it("repays USDC to DYTM market", async () => {
|
|
206
|
+
await pool.repay(Dapp.DYTM, USDC_BORROW_TOKEN, (1 * 1e6).toString());
|
|
207
|
+
|
|
208
|
+
const usdcTokenDelta = await balanceDelta(
|
|
209
|
+
pool.address,
|
|
210
|
+
USDC,
|
|
211
|
+
pool.signer
|
|
212
|
+
);
|
|
213
|
+
expect(usdcTokenDelta.lt(0)).toBe(true);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it("withdraws USDC from DYTM market", async () => {
|
|
217
|
+
await pool.withdrawDeposit(
|
|
218
|
+
Dapp.DYTM,
|
|
219
|
+
USDC_DEPOSIT_TOKEN,
|
|
220
|
+
(5 * 1e6).toString()
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
const usdcTokenDelta = await balanceDelta(
|
|
224
|
+
pool.address,
|
|
225
|
+
USDC,
|
|
226
|
+
pool.signer
|
|
227
|
+
);
|
|
228
|
+
expect(usdcTokenDelta.gt(0)).toBe(true);
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
testingHelper({
|
|
234
|
+
network: Network.ARBITRUM,
|
|
235
|
+
testingRun: testDytm
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
testingHelper({
|
|
239
|
+
network: Network.ETHEREUM,
|
|
240
|
+
testingRun: testDytm
|
|
241
|
+
});
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Ondo Global Markets on-chain tests for minting and redeeming GM tokens.
|
|
5
|
+
* These require a live chain connection (onFork: false) because each mint/redeem
|
|
6
|
+
* needs a fresh attestation signed by the Ondo API against current chain state,
|
|
7
|
+
* which cannot be reproduced on a Hardhat fork.
|
|
8
|
+
*
|
|
9
|
+
* Prerequisites:
|
|
10
|
+
* - PRIVATE_KEY in .env (must be the pool manager or trader)
|
|
11
|
+
* - ETHEREUM_URL in .env
|
|
12
|
+
* - ONDO_API_KEY in .env
|
|
13
|
+
* - The test pool must hold USDC to mint (and SPYon, from the mint, to redeem)
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { ethers } from "ethers";
|
|
17
|
+
import { Dhedge, Pool } from "..";
|
|
18
|
+
|
|
19
|
+
import { Dapp, Network } from "../types";
|
|
20
|
+
import { CONTRACT_ADDRESS, MAX_AMOUNT } from "./constants";
|
|
21
|
+
import { TestingRunParams, testingHelper } from "./utils/testingHelper";
|
|
22
|
+
|
|
23
|
+
import { getTxOptions } from "./txOptions";
|
|
24
|
+
import { balanceDelta } from "./utils/token";
|
|
25
|
+
|
|
26
|
+
import { routerAddress } from "../config";
|
|
27
|
+
|
|
28
|
+
const testOndo = ({ wallet, network }: TestingRunParams) => {
|
|
29
|
+
const USDC = CONTRACT_ADDRESS[network].USDC;
|
|
30
|
+
const SPYon = "0xfedc5f4a6c38211c1338aa411018dfaf26612c08";
|
|
31
|
+
|
|
32
|
+
let dhedge: Dhedge;
|
|
33
|
+
let pool: Pool;
|
|
34
|
+
jest.setTimeout(100000);
|
|
35
|
+
|
|
36
|
+
describe(`pool on ${network}`, () => {
|
|
37
|
+
beforeAll(async () => {
|
|
38
|
+
dhedge = new Dhedge(wallet, network);
|
|
39
|
+
pool = await dhedge.loadPool(
|
|
40
|
+
"0x9f647b85A514b1e60F8E8E956E636a50dA406279"
|
|
41
|
+
);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("approves unlimited USDC on Ondo", async () => {
|
|
45
|
+
const tx = await pool.approve(Dapp.ONDO, USDC, MAX_AMOUNT);
|
|
46
|
+
await tx.wait();
|
|
47
|
+
const iERC20 = new ethers.Contract(
|
|
48
|
+
USDC,
|
|
49
|
+
["function allowance(address,address) view returns (uint256)"],
|
|
50
|
+
pool.signer
|
|
51
|
+
);
|
|
52
|
+
const allowance = await iERC20.allowance(
|
|
53
|
+
pool.address,
|
|
54
|
+
routerAddress[network][Dapp.ONDO]!
|
|
55
|
+
);
|
|
56
|
+
expect(allowance.gt(0)).toBe(true);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("gets gas estimation for 40 USDC into SPYon on Ondo", async () => {
|
|
60
|
+
const gasEstimate = await pool.trade(
|
|
61
|
+
Dapp.ONDO,
|
|
62
|
+
USDC,
|
|
63
|
+
SPYon,
|
|
64
|
+
"40000000",
|
|
65
|
+
0.1,
|
|
66
|
+
await getTxOptions(network),
|
|
67
|
+
true
|
|
68
|
+
);
|
|
69
|
+
expect(gasEstimate.gasEstimationError).toBeNull();
|
|
70
|
+
expect(gasEstimate.gas.gt(0)).toBe(true);
|
|
71
|
+
expect(gasEstimate.minAmountOut).not.toBeNull();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("trades 40 USDC into SPYon on Ondo", async () => {
|
|
75
|
+
const tx = await pool.trade(
|
|
76
|
+
Dapp.ONDO,
|
|
77
|
+
USDC,
|
|
78
|
+
SPYon,
|
|
79
|
+
"40000000",
|
|
80
|
+
0.1,
|
|
81
|
+
await getTxOptions(network)
|
|
82
|
+
);
|
|
83
|
+
await tx.wait();
|
|
84
|
+
const spBalanceDelta = await balanceDelta(
|
|
85
|
+
pool.address,
|
|
86
|
+
SPYon,
|
|
87
|
+
pool.signer
|
|
88
|
+
);
|
|
89
|
+
expect(spBalanceDelta.gt(0)).toBe(true);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it("approves unlimited SPYon on Ondo", async () => {
|
|
93
|
+
const tx = await pool.approve(Dapp.ONDO, SPYon, MAX_AMOUNT);
|
|
94
|
+
await tx.wait();
|
|
95
|
+
const iERC20 = new ethers.Contract(
|
|
96
|
+
SPYon,
|
|
97
|
+
["function allowance(address,address) view returns (uint256)"],
|
|
98
|
+
pool.signer
|
|
99
|
+
);
|
|
100
|
+
const allowance = await iERC20.allowance(
|
|
101
|
+
pool.address,
|
|
102
|
+
routerAddress[network][Dapp.ONDO]!
|
|
103
|
+
);
|
|
104
|
+
expect(allowance.gt(0)).toBe(true);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("sells SPYon balance on Ondo", async () => {
|
|
108
|
+
const spyonBalance = await pool.utils.getBalance(SPYon, pool.address);
|
|
109
|
+
const tx = await pool.trade(
|
|
110
|
+
Dapp.ONDO,
|
|
111
|
+
SPYon,
|
|
112
|
+
USDC,
|
|
113
|
+
spyonBalance,
|
|
114
|
+
0.1,
|
|
115
|
+
await getTxOptions(network)
|
|
116
|
+
);
|
|
117
|
+
await tx.wait();
|
|
118
|
+
const usdcBalanceDelta = await balanceDelta(
|
|
119
|
+
pool.address,
|
|
120
|
+
USDC,
|
|
121
|
+
pool.signer
|
|
122
|
+
);
|
|
123
|
+
expect(usdcBalanceDelta.gt(0)).toBe(true);
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
testingHelper({
|
|
129
|
+
network: Network.ETHEREUM,
|
|
130
|
+
testingRun: testOndo,
|
|
131
|
+
onFork: false
|
|
132
|
+
});
|
package/src/types.ts
CHANGED
|
@@ -36,8 +36,10 @@ export enum Dapp {
|
|
|
36
36
|
ODOS = "odos",
|
|
37
37
|
PENDLE = "pendle",
|
|
38
38
|
KYBERSWAP = "kyberswap",
|
|
39
|
+
DYTM = "dytm",
|
|
39
40
|
HYPERLIQUID = "hyperliquid",
|
|
40
|
-
COWSWAP = "cowswap"
|
|
41
|
+
COWSWAP = "cowswap",
|
|
42
|
+
ONDO = "ondo"
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
/** Function-name strings used when encoding ABI calls — keep in sync with the
|