@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
package/package.json
CHANGED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"inputs": [
|
|
4
|
+
{
|
|
5
|
+
"components": [
|
|
6
|
+
{
|
|
7
|
+
"internalType": "AccountId",
|
|
8
|
+
"name": "account",
|
|
9
|
+
"type": "uint256"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"internalType": "ReserveKey",
|
|
13
|
+
"name": "key",
|
|
14
|
+
"type": "uint248"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"internalType": "address",
|
|
18
|
+
"name": "receiver",
|
|
19
|
+
"type": "address"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"internalType": "uint256",
|
|
23
|
+
"name": "assets",
|
|
24
|
+
"type": "uint256"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"internalType": "bytes",
|
|
28
|
+
"name": "extraData",
|
|
29
|
+
"type": "bytes"
|
|
30
|
+
}
|
|
31
|
+
],
|
|
32
|
+
"internalType": "struct BorrowParams",
|
|
33
|
+
"name": "params",
|
|
34
|
+
"type": "tuple"
|
|
35
|
+
}
|
|
36
|
+
],
|
|
37
|
+
"name": "borrow",
|
|
38
|
+
"outputs": [
|
|
39
|
+
{
|
|
40
|
+
"internalType": "uint256",
|
|
41
|
+
"name": "debtShares",
|
|
42
|
+
"type": "uint256"
|
|
43
|
+
}
|
|
44
|
+
],
|
|
45
|
+
"stateMutability": "nonpayable",
|
|
46
|
+
"type": "function"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"inputs": [
|
|
50
|
+
{
|
|
51
|
+
"components": [
|
|
52
|
+
{
|
|
53
|
+
"internalType": "AccountId",
|
|
54
|
+
"name": "account",
|
|
55
|
+
"type": "uint256"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"internalType": "ReserveKey",
|
|
59
|
+
"name": "key",
|
|
60
|
+
"type": "uint248"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"internalType": "enum TokenType",
|
|
64
|
+
"name": "withCollateralType",
|
|
65
|
+
"type": "uint8"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"internalType": "uint256",
|
|
69
|
+
"name": "assets",
|
|
70
|
+
"type": "uint256"
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"internalType": "uint256",
|
|
74
|
+
"name": "shares",
|
|
75
|
+
"type": "uint256"
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"internalType": "bytes",
|
|
79
|
+
"name": "extraData",
|
|
80
|
+
"type": "bytes"
|
|
81
|
+
}
|
|
82
|
+
],
|
|
83
|
+
"internalType": "struct RepayParams",
|
|
84
|
+
"name": "params",
|
|
85
|
+
"type": "tuple"
|
|
86
|
+
}
|
|
87
|
+
],
|
|
88
|
+
"name": "repay",
|
|
89
|
+
"outputs": [
|
|
90
|
+
{
|
|
91
|
+
"internalType": "uint256",
|
|
92
|
+
"name": "assetsRepaid",
|
|
93
|
+
"type": "uint256"
|
|
94
|
+
}
|
|
95
|
+
],
|
|
96
|
+
"stateMutability": "nonpayable",
|
|
97
|
+
"type": "function"
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"inputs": [
|
|
101
|
+
{
|
|
102
|
+
"components": [
|
|
103
|
+
{
|
|
104
|
+
"internalType": "AccountId",
|
|
105
|
+
"name": "account",
|
|
106
|
+
"type": "uint256"
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"internalType": "uint256",
|
|
110
|
+
"name": "tokenId",
|
|
111
|
+
"type": "uint256"
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"internalType": "uint256",
|
|
115
|
+
"name": "assets",
|
|
116
|
+
"type": "uint256"
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
"internalType": "bytes",
|
|
120
|
+
"name": "extraData",
|
|
121
|
+
"type": "bytes"
|
|
122
|
+
}
|
|
123
|
+
],
|
|
124
|
+
"internalType": "struct SupplyParams",
|
|
125
|
+
"name": "params",
|
|
126
|
+
"type": "tuple"
|
|
127
|
+
}
|
|
128
|
+
],
|
|
129
|
+
"name": "supply",
|
|
130
|
+
"outputs": [
|
|
131
|
+
{
|
|
132
|
+
"internalType": "uint256",
|
|
133
|
+
"name": "shares",
|
|
134
|
+
"type": "uint256"
|
|
135
|
+
}
|
|
136
|
+
],
|
|
137
|
+
"stateMutability": "nonpayable",
|
|
138
|
+
"type": "function"
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
"inputs": [
|
|
142
|
+
{
|
|
143
|
+
"components": [
|
|
144
|
+
{
|
|
145
|
+
"internalType": "AccountId",
|
|
146
|
+
"name": "account",
|
|
147
|
+
"type": "uint256"
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
"internalType": "uint256",
|
|
151
|
+
"name": "tokenId",
|
|
152
|
+
"type": "uint256"
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
"internalType": "address",
|
|
156
|
+
"name": "receiver",
|
|
157
|
+
"type": "address"
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"internalType": "uint256",
|
|
161
|
+
"name": "assets",
|
|
162
|
+
"type": "uint256"
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
"internalType": "uint256",
|
|
166
|
+
"name": "shares",
|
|
167
|
+
"type": "uint256"
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
"internalType": "bytes",
|
|
171
|
+
"name": "extraData",
|
|
172
|
+
"type": "bytes"
|
|
173
|
+
}
|
|
174
|
+
],
|
|
175
|
+
"internalType": "struct WithdrawParams",
|
|
176
|
+
"name": "params",
|
|
177
|
+
"type": "tuple"
|
|
178
|
+
}
|
|
179
|
+
],
|
|
180
|
+
"name": "withdraw",
|
|
181
|
+
"outputs": [
|
|
182
|
+
{
|
|
183
|
+
"internalType": "uint256",
|
|
184
|
+
"name": "assets",
|
|
185
|
+
"type": "uint256"
|
|
186
|
+
}
|
|
187
|
+
],
|
|
188
|
+
"stateMutability": "nonpayable",
|
|
189
|
+
"type": "function"
|
|
190
|
+
}
|
|
191
|
+
]
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"inputs": [
|
|
4
|
+
{ "name": "tokenIn", "type": "address" },
|
|
5
|
+
{ "name": "amountIn", "type": "uint256" },
|
|
6
|
+
{ "name": "tokenOut", "type": "address" },
|
|
7
|
+
{ "name": "amountOutMinimum", "type": "uint256" },
|
|
8
|
+
{ "name": "attestationSignature", "type": "bytes" },
|
|
9
|
+
{
|
|
10
|
+
"components": [
|
|
11
|
+
{ "name": "chainId", "type": "uint256" },
|
|
12
|
+
{ "name": "attestationId", "type": "uint256" },
|
|
13
|
+
{ "name": "userId", "type": "bytes32" },
|
|
14
|
+
{ "name": "asset", "type": "address" },
|
|
15
|
+
{ "name": "price", "type": "uint256" },
|
|
16
|
+
{ "name": "quantity", "type": "uint256" },
|
|
17
|
+
{ "name": "expiration", "type": "uint256" },
|
|
18
|
+
{ "name": "side", "type": "uint8" },
|
|
19
|
+
{ "name": "additionalData", "type": "bytes32" }
|
|
20
|
+
],
|
|
21
|
+
"name": "quote",
|
|
22
|
+
"type": "tuple"
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
"name": "swapExactInWithAttestation",
|
|
26
|
+
"outputs": [],
|
|
27
|
+
"stateMutability": "nonpayable",
|
|
28
|
+
"type": "function"
|
|
29
|
+
}
|
|
30
|
+
]
|
package/src/config.ts
CHANGED
|
@@ -61,7 +61,8 @@ export const routerAddress: AddressDappNetworkMap = {
|
|
|
61
61
|
[Dapp.TOROS]: "0xA5679C4272A056Bb83f039961fae7D99C48529F5",
|
|
62
62
|
[Dapp.ODOS]: "0x0D05a7D3448512B78fa8A9e46c4872C88C4a0D05",
|
|
63
63
|
[Dapp.PENDLE]: "0x888888888889758F76e7103c6CbF23ABbF58F946",
|
|
64
|
-
[Dapp.KYBERSWAP]: "0x6131B5fae19EA4f9D964eAc0408E4408b66337b5"
|
|
64
|
+
[Dapp.KYBERSWAP]: "0x6131B5fae19EA4f9D964eAc0408E4408b66337b5",
|
|
65
|
+
[Dapp.DYTM]: "0x0fF1CEE337d7af25eEF4c1a7A2CaF83f98d80001"
|
|
65
66
|
},
|
|
66
67
|
[Network.BASE]: {
|
|
67
68
|
[Dapp.ONEINCH]: "0x111111125421ca6dc452d289314280a0f8842a65",
|
|
@@ -77,7 +78,9 @@ export const routerAddress: AddressDappNetworkMap = {
|
|
|
77
78
|
[Dapp.ODOS]: "0x0D05a7D3448512B78fa8A9e46c4872C88C4a0D05",
|
|
78
79
|
[Dapp.PENDLE]: "0x888888888889758F76e7103c6CbF23ABbF58F946",
|
|
79
80
|
[Dapp.ONEINCH]: "0x111111125421ca6dc452d289314280a0f8842a65",
|
|
80
|
-
[Dapp.KYBERSWAP]: "0x6131B5fae19EA4f9D964eAc0408E4408b66337b5"
|
|
81
|
+
[Dapp.KYBERSWAP]: "0x6131B5fae19EA4f9D964eAc0408E4408b66337b5",
|
|
82
|
+
[Dapp.ONDO]: "0xde41399145F23936b03dD1474eC16c1519c0DC2a",
|
|
83
|
+
[Dapp.DYTM]: "0x0ff1ce991105DD1a8e26bC8a974Fd0154398Df0f"
|
|
81
84
|
},
|
|
82
85
|
[Network.PLASMA]: {
|
|
83
86
|
[Dapp.AAVEV3]: "0x925a2A7214Ed92428B5b1B090F80b25700095e12",
|
|
@@ -275,3 +278,19 @@ export const OdosSwapFeeRecipient = {
|
|
|
275
278
|
[Network.PLASMA]: "",
|
|
276
279
|
[Network.HYPERLIQUID]: ""
|
|
277
280
|
};
|
|
281
|
+
|
|
282
|
+
export const dytmContractAddresses: Readonly<Partial<
|
|
283
|
+
Record<
|
|
284
|
+
Network,
|
|
285
|
+
{
|
|
286
|
+
Periphery?: string;
|
|
287
|
+
}
|
|
288
|
+
>
|
|
289
|
+
>> = {
|
|
290
|
+
[Network.ARBITRUM]: {
|
|
291
|
+
Periphery: "0x1FBe7Bb394BE505C08e9ee419Dd166c71004e51B"
|
|
292
|
+
},
|
|
293
|
+
[Network.ETHEREUM]: {
|
|
294
|
+
Periphery: "0xbc632a1A4bD878D7e7D14ea6CfE0DDe3Fc291D1a"
|
|
295
|
+
}
|
|
296
|
+
};
|
package/src/entities/pool.ts
CHANGED
|
@@ -77,7 +77,17 @@ import {
|
|
|
77
77
|
} from "../services/pancake/staking";
|
|
78
78
|
import { getOdosSwapTxData } from "../services/odos";
|
|
79
79
|
import { getPendleMintTxData, getPendleSwapTxData } from "../services/pendle";
|
|
80
|
-
import {
|
|
80
|
+
import {
|
|
81
|
+
getCompleteWithdrawalTxData,
|
|
82
|
+
TrackedAsset
|
|
83
|
+
} from "../services/toros/completeWithdrawal";
|
|
84
|
+
import {
|
|
85
|
+
getDytmBorrowTxData,
|
|
86
|
+
getDytmDepositTxData,
|
|
87
|
+
getDytmRepayTxData,
|
|
88
|
+
getDytmWithdrawTxData
|
|
89
|
+
} from "../services/dytm";
|
|
90
|
+
|
|
81
91
|
import {
|
|
82
92
|
getCreateLimitOrderTxData,
|
|
83
93
|
getModifyLimitOrderTxData,
|
|
@@ -87,6 +97,7 @@ import {
|
|
|
87
97
|
} from "../services/toros/limitOrder";
|
|
88
98
|
import { getKyberSwapTxData } from "../services/kyberSwap";
|
|
89
99
|
import { getCowSwapTxData } from "../services/cowSwap";
|
|
100
|
+
import { getOndoSwapTxData } from "../services/ondo";
|
|
90
101
|
import {
|
|
91
102
|
getClosePositionHyperliquidTxData,
|
|
92
103
|
getDepositHyperliquidTxData,
|
|
@@ -416,13 +427,13 @@ export class Pool {
|
|
|
416
427
|
);
|
|
417
428
|
break;
|
|
418
429
|
case Dapp.TOROS:
|
|
419
|
-
swapTxData = await getEasySwapperTxData(
|
|
430
|
+
({ swapTxData, minAmountOut } = await getEasySwapperTxData(
|
|
420
431
|
this,
|
|
421
432
|
assetFrom,
|
|
422
433
|
assetTo,
|
|
423
434
|
ethers.BigNumber.from(amountIn),
|
|
424
435
|
slippage
|
|
425
|
-
);
|
|
436
|
+
));
|
|
426
437
|
break;
|
|
427
438
|
case Dapp.ODOS:
|
|
428
439
|
({ swapTxData, minAmountOut } = await getOdosSwapTxData(
|
|
@@ -451,6 +462,15 @@ export class Pool {
|
|
|
451
462
|
slippage
|
|
452
463
|
));
|
|
453
464
|
break;
|
|
465
|
+
case Dapp.ONDO:
|
|
466
|
+
({ swapTxData, minAmountOut } = await getOndoSwapTxData(
|
|
467
|
+
this,
|
|
468
|
+
assetFrom,
|
|
469
|
+
assetTo,
|
|
470
|
+
amountIn.toString(),
|
|
471
|
+
slippage
|
|
472
|
+
));
|
|
473
|
+
break;
|
|
454
474
|
case Dapp.COWSWAP: {
|
|
455
475
|
const cowSwapEstimateGas = isSdkOptionsBoolean(sdkOptions)
|
|
456
476
|
? sdkOptions
|
|
@@ -786,13 +806,18 @@ export class Pool {
|
|
|
786
806
|
estimateGas: false
|
|
787
807
|
}
|
|
788
808
|
): Promise<any> {
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
asset,
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
809
|
+
let depositTxData: string;
|
|
810
|
+
if (dapp === Dapp.DYTM) {
|
|
811
|
+
depositTxData = getDytmDepositTxData(this, asset, amount);
|
|
812
|
+
} else {
|
|
813
|
+
const iLendingPool = new ethers.utils.Interface(ILendingPool.abi);
|
|
814
|
+
depositTxData = iLendingPool.encodeFunctionData(Transaction.DEPOSIT, [
|
|
815
|
+
asset,
|
|
816
|
+
amount,
|
|
817
|
+
this.address,
|
|
818
|
+
referralCode
|
|
819
|
+
]);
|
|
820
|
+
}
|
|
796
821
|
|
|
797
822
|
const tx = await getPoolTxOrGasEstimate(
|
|
798
823
|
this,
|
|
@@ -853,11 +878,17 @@ export class Pool {
|
|
|
853
878
|
estimateGas: false
|
|
854
879
|
}
|
|
855
880
|
): Promise<any> {
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
881
|
+
let withdrawTxData: string;
|
|
882
|
+
if (dapp === Dapp.DYTM) {
|
|
883
|
+
withdrawTxData = await getDytmWithdrawTxData(this, asset, amount);
|
|
884
|
+
} else {
|
|
885
|
+
const iLendingPool = new ethers.utils.Interface(ILendingPool.abi);
|
|
886
|
+
withdrawTxData = iLendingPool.encodeFunctionData(Transaction.WITHDRAW, [
|
|
887
|
+
asset,
|
|
888
|
+
amount,
|
|
889
|
+
this.address
|
|
890
|
+
]);
|
|
891
|
+
}
|
|
861
892
|
|
|
862
893
|
const tx = await getPoolTxOrGasEstimate(
|
|
863
894
|
this,
|
|
@@ -920,14 +951,19 @@ export class Pool {
|
|
|
920
951
|
estimateGas: false
|
|
921
952
|
}
|
|
922
953
|
): Promise<any> {
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
asset,
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
954
|
+
let borrowTxData: string;
|
|
955
|
+
if (dapp === Dapp.DYTM) {
|
|
956
|
+
borrowTxData = getDytmBorrowTxData(this, asset, amount);
|
|
957
|
+
} else {
|
|
958
|
+
const iLendingPool = new ethers.utils.Interface(ILendingPool.abi);
|
|
959
|
+
borrowTxData = iLendingPool.encodeFunctionData(Transaction.BORROW, [
|
|
960
|
+
asset,
|
|
961
|
+
amount,
|
|
962
|
+
2,
|
|
963
|
+
referralCode,
|
|
964
|
+
this.address
|
|
965
|
+
]);
|
|
966
|
+
}
|
|
931
967
|
const tx = await getPoolTxOrGasEstimate(
|
|
932
968
|
this,
|
|
933
969
|
[routerAddress[this.network][dapp], borrowTxData, options],
|
|
@@ -954,13 +990,18 @@ export class Pool {
|
|
|
954
990
|
estimateGas: false
|
|
955
991
|
}
|
|
956
992
|
): Promise<any> {
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
asset,
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
993
|
+
let repayTxData: string;
|
|
994
|
+
if (dapp === Dapp.DYTM) {
|
|
995
|
+
repayTxData = await getDytmRepayTxData(this, asset, amount);
|
|
996
|
+
} else {
|
|
997
|
+
const iLendingPool = new ethers.utils.Interface(ILendingPool.abi);
|
|
998
|
+
repayTxData = iLendingPool.encodeFunctionData(Transaction.REPAY, [
|
|
999
|
+
asset,
|
|
1000
|
+
amount,
|
|
1001
|
+
2,
|
|
1002
|
+
this.address
|
|
1003
|
+
]);
|
|
1004
|
+
}
|
|
964
1005
|
const tx = await getPoolTxOrGasEstimate(
|
|
965
1006
|
this,
|
|
966
1007
|
[routerAddress[this.network][dapp], repayTxData, options],
|
|
@@ -1953,6 +1994,7 @@ export class Pool {
|
|
|
1953
1994
|
* @param {number} slippage Slippage tolerance in %
|
|
1954
1995
|
* @param {any} options Transaction options
|
|
1955
1996
|
* @param {SDKOptions} sdkOptions SDK options including estimateGas
|
|
1997
|
+
* @param {any} trackedAssets Tracked assets information (only for tx data generation)
|
|
1956
1998
|
* @returns {Promise<any>} Transaction
|
|
1957
1999
|
*/
|
|
1958
2000
|
async completeTorosWithdrawal(
|
|
@@ -1961,13 +2003,15 @@ export class Pool {
|
|
|
1961
2003
|
options: any = null,
|
|
1962
2004
|
sdkOptions: SDKOptions = {
|
|
1963
2005
|
estimateGas: false
|
|
1964
|
-
}
|
|
2006
|
+
},
|
|
2007
|
+
trackedAssets: TrackedAsset[] = []
|
|
1965
2008
|
): Promise<any> {
|
|
1966
2009
|
const txData = await getCompleteWithdrawalTxData(
|
|
1967
2010
|
this,
|
|
1968
2011
|
destinationToken,
|
|
1969
2012
|
slippage * 100,
|
|
1970
|
-
false
|
|
2013
|
+
false,
|
|
2014
|
+
trackedAssets
|
|
1971
2015
|
);
|
|
1972
2016
|
const tx = await getPoolTxOrGasEstimate(
|
|
1973
2017
|
this,
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { ethers } from "ethers";
|
|
2
|
+
import IOffice from "../../abi/dytm/IOffice.json";
|
|
3
|
+
import { Pool } from "../../entities";
|
|
4
|
+
|
|
5
|
+
const iOffice = new ethers.utils.Interface(IOffice);
|
|
6
|
+
|
|
7
|
+
export function toDebtId(key: ethers.BigNumber): ethers.BigNumber {
|
|
8
|
+
const tokenTypeBits = ethers.BigNumber.from(3).shl(248);
|
|
9
|
+
return tokenTypeBits.or(key);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const getDytmDepositTxData = (
|
|
13
|
+
pool: Pool,
|
|
14
|
+
asset: string,
|
|
15
|
+
amount: ethers.BigNumber | string
|
|
16
|
+
): string => {
|
|
17
|
+
return iOffice.encodeFunctionData("supply", [
|
|
18
|
+
{
|
|
19
|
+
account: ethers.BigNumber.from(pool.address), // uint256 (converted address)
|
|
20
|
+
tokenId: asset,
|
|
21
|
+
assets: amount,
|
|
22
|
+
extraData: "0x"
|
|
23
|
+
}
|
|
24
|
+
]);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const getDytmBorrowTxData = (
|
|
28
|
+
pool: Pool,
|
|
29
|
+
asset: string,
|
|
30
|
+
amount: ethers.BigNumber | string
|
|
31
|
+
): string => {
|
|
32
|
+
return iOffice.encodeFunctionData("borrow", [
|
|
33
|
+
{
|
|
34
|
+
account: ethers.BigNumber.from(pool.address), // uint256 (converted address)
|
|
35
|
+
key: asset,
|
|
36
|
+
receiver: pool.address,
|
|
37
|
+
assets: amount,
|
|
38
|
+
extraData: "0x"
|
|
39
|
+
}
|
|
40
|
+
]);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const getDytmRepayTxData = async (
|
|
44
|
+
pool: Pool,
|
|
45
|
+
asset: string,
|
|
46
|
+
amount: ethers.BigNumber | string
|
|
47
|
+
): Promise<string> => {
|
|
48
|
+
return iOffice.encodeFunctionData("repay", [
|
|
49
|
+
{
|
|
50
|
+
account: ethers.BigNumber.from(pool.address), // uint256 (converted address)
|
|
51
|
+
key: asset,
|
|
52
|
+
withCollateralType: "0",
|
|
53
|
+
assets: amount,
|
|
54
|
+
shares: "0",
|
|
55
|
+
extraData: "0x"
|
|
56
|
+
}
|
|
57
|
+
]);
|
|
58
|
+
};
|
|
59
|
+
export const getDytmWithdrawTxData = async (
|
|
60
|
+
pool: Pool,
|
|
61
|
+
asset: string,
|
|
62
|
+
amount: ethers.BigNumber | string
|
|
63
|
+
): Promise<string> => {
|
|
64
|
+
const isMaxAmount = ethers.BigNumber.from(amount).eq(
|
|
65
|
+
ethers.constants.MaxUint256
|
|
66
|
+
);
|
|
67
|
+
return iOffice.encodeFunctionData("withdraw", [
|
|
68
|
+
{
|
|
69
|
+
account: ethers.BigNumber.from(pool.address), // uint256 (converted address)
|
|
70
|
+
tokenId: asset,
|
|
71
|
+
assets: isMaxAmount ? 0 : amount,
|
|
72
|
+
shares: isMaxAmount ? amount : 0,
|
|
73
|
+
receiver: pool.address,
|
|
74
|
+
extraData: "0x"
|
|
75
|
+
}
|
|
76
|
+
]);
|
|
77
|
+
};
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import { ethers } from "ethers";
|
|
3
|
+
import BigNumber from "bignumber.js";
|
|
4
|
+
import { ApiError, Pool } from "../..";
|
|
5
|
+
import IOndoGMSwap from "../../abi/ondo/IOndoGMSwap.json";
|
|
6
|
+
|
|
7
|
+
const ONDO_API_URL = "https://api.gm.ondo.finance/v1/attestations";
|
|
8
|
+
|
|
9
|
+
// Ethereum mainnet USDC — Ondo is Ethereum-only
|
|
10
|
+
const USDC_ETHEREUM = "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48";
|
|
11
|
+
|
|
12
|
+
type OndoAttestation = {
|
|
13
|
+
attestationId: string;
|
|
14
|
+
userId: string;
|
|
15
|
+
chainId: string;
|
|
16
|
+
assetAddress: string;
|
|
17
|
+
side: string;
|
|
18
|
+
tokenAmount: string;
|
|
19
|
+
price: string;
|
|
20
|
+
expiration: number;
|
|
21
|
+
signature: string;
|
|
22
|
+
additionalData: string;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const iface = new ethers.utils.Interface(IOndoGMSwap);
|
|
26
|
+
|
|
27
|
+
// Ondo returns userId as a left-aligned 32-byte hex (significant bytes first,
|
|
28
|
+
// e.g. 0x474d...0000), so right-pad to preserve byte order and fix it to 32 bytes.
|
|
29
|
+
function toBytes32(s: string): string {
|
|
30
|
+
const hex = s.startsWith("0x") ? s.slice(2) : s;
|
|
31
|
+
return "0x" + hex.padEnd(64, "0").slice(0, 64);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function postOndoAttestation(
|
|
35
|
+
symbol: string,
|
|
36
|
+
side: "buy" | "sell",
|
|
37
|
+
amount: { notionalValue: string } | { tokenAmount: string },
|
|
38
|
+
apiKey: string
|
|
39
|
+
): Promise<OndoAttestation> {
|
|
40
|
+
try {
|
|
41
|
+
const { data } = await axios.post(
|
|
42
|
+
ONDO_API_URL,
|
|
43
|
+
{ chainId: "ethereum-1", symbol, side, ...amount, duration: "short" },
|
|
44
|
+
{ headers: { "x-api-key": apiKey } }
|
|
45
|
+
);
|
|
46
|
+
return data as OndoAttestation;
|
|
47
|
+
} catch (error) {
|
|
48
|
+
// Surface Ondo's structured error (e.g. ASSET_NOT_FOUND, MARKET_CLOSED)
|
|
49
|
+
if (axios.isAxiosError(error) && error.response) {
|
|
50
|
+
const { code, message } = error.response.data ?? {};
|
|
51
|
+
throw new ApiError(
|
|
52
|
+
`Ondo attestation request failed (${error.response.status}): ${code ??
|
|
53
|
+
""} ${message ?? JSON.stringify(error.response.data)}`.trim()
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
throw new ApiError(
|
|
57
|
+
`Ondo attestation request failed: ${
|
|
58
|
+
error instanceof Error ? error.message : String(error)
|
|
59
|
+
}`
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export async function getOndoSwapTxData(
|
|
65
|
+
pool: Pool,
|
|
66
|
+
tokenIn: string,
|
|
67
|
+
tokenOut: string,
|
|
68
|
+
amountIn: string,
|
|
69
|
+
slippage: number
|
|
70
|
+
): Promise<{ swapTxData: string; minAmountOut: string }> {
|
|
71
|
+
const apiKey = process.env.ONDO_API_KEY;
|
|
72
|
+
if (!apiKey) throw new Error("ONDO_API_KEY environment variable is not set");
|
|
73
|
+
|
|
74
|
+
const amount = new BigNumber(amountIn);
|
|
75
|
+
const isMint = tokenIn.toLowerCase() === USDC_ETHEREUM.toLowerCase();
|
|
76
|
+
const gmToken = isMint ? tokenOut : tokenIn;
|
|
77
|
+
const slippageBps = Math.round(slippage * 100);
|
|
78
|
+
|
|
79
|
+
const tokenContract = new ethers.Contract(
|
|
80
|
+
gmToken,
|
|
81
|
+
["function symbol() view returns (string)"],
|
|
82
|
+
pool.signer
|
|
83
|
+
);
|
|
84
|
+
const symbol: string = await tokenContract.symbol();
|
|
85
|
+
|
|
86
|
+
// For mint: notionalValue is the USD amount to subscribe. USDonManager values
|
|
87
|
+
// USDC at par (1 USDC = 1 USDon), so pass the USDC amount as-is (6dp -> decimal).
|
|
88
|
+
// Discounting by a USDC market price would strand the gap as USDon in the swapper
|
|
89
|
+
// (and revert via ExcessiveAmountIn once it exceeds the 1 USDC tolerance).
|
|
90
|
+
// For redeem: pass the GM token amount directly as tokenAmount.
|
|
91
|
+
const attestationAmount = isMint
|
|
92
|
+
? { notionalValue: amount.div(1e6).toFixed(18) }
|
|
93
|
+
: { tokenAmount: amount.div(1e18).toFixed(18) };
|
|
94
|
+
|
|
95
|
+
const attestation = await postOndoAttestation(
|
|
96
|
+
symbol,
|
|
97
|
+
isMint ? "buy" : "sell",
|
|
98
|
+
attestationAmount,
|
|
99
|
+
apiKey
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
const signature =
|
|
103
|
+
"0x" + Buffer.from(attestation.signature, "base64").toString("hex");
|
|
104
|
+
const additionalData = ethers.utils.hexZeroPad(
|
|
105
|
+
"0x" + Buffer.from(attestation.additionalData, "base64").toString("hex"),
|
|
106
|
+
32
|
|
107
|
+
);
|
|
108
|
+
const quantity = new BigNumber(attestation.tokenAmount);
|
|
109
|
+
const priceD18 = new BigNumber(attestation.price);
|
|
110
|
+
|
|
111
|
+
let minAmountOut: BigNumber;
|
|
112
|
+
if (isMint) {
|
|
113
|
+
minAmountOut = quantity.times(10000 - slippageBps).div(10000);
|
|
114
|
+
} else {
|
|
115
|
+
// USDC out (6 dec) = quantity_D18 * price_D18 / 1e30
|
|
116
|
+
const usdcOut = quantity.times(priceD18).div(1e30);
|
|
117
|
+
minAmountOut = usdcOut.times(10000 - slippageBps).div(10000);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const quote = {
|
|
121
|
+
chainId: 1,
|
|
122
|
+
attestationId: attestation.attestationId,
|
|
123
|
+
userId: toBytes32(attestation.userId),
|
|
124
|
+
asset: attestation.assetAddress,
|
|
125
|
+
price: priceD18.toFixed(0),
|
|
126
|
+
quantity: quantity.toFixed(0),
|
|
127
|
+
expiration: attestation.expiration,
|
|
128
|
+
side: Number(attestation.side),
|
|
129
|
+
additionalData
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const swapTxData = iface.encodeFunctionData("swapExactInWithAttestation", [
|
|
133
|
+
tokenIn,
|
|
134
|
+
amount.toFixed(0),
|
|
135
|
+
tokenOut,
|
|
136
|
+
minAmountOut.toFixed(0),
|
|
137
|
+
signature,
|
|
138
|
+
quote
|
|
139
|
+
]);
|
|
140
|
+
|
|
141
|
+
return { swapTxData, minAmountOut: minAmountOut.toFixed(0) };
|
|
142
|
+
}
|