@varla/sdk 3.2.0 → 4.1.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/AGENTS.md +9 -9
- package/CHANGELOG.md +35 -0
- package/dist/abi/full/VarlaCore.d.ts +44 -60
- package/dist/abi/full/VarlaCore.d.ts.map +1 -1
- package/dist/abi/full/VarlaCore.js +55 -77
- package/dist/abi/full/VarlaCore.js.map +1 -1
- package/dist/abi/full/VarlaLiquidator.d.ts +1 -1
- package/dist/abi/full/VarlaLiquidator.js +1 -1
- package/dist/abi/full/VarlaLiquidator.js.map +1 -1
- package/dist/actions/core.d.ts +35 -0
- package/dist/actions/core.d.ts.map +1 -1
- package/dist/actions/core.js +36 -5
- package/dist/actions/core.js.map +1 -1
- package/dist/actions/erc1155.d.ts +73 -0
- package/dist/actions/erc1155.d.ts.map +1 -1
- package/dist/actions/erc1155.js +74 -0
- package/dist/actions/erc1155.js.map +1 -1
- package/dist/addresses/polygon.js +11 -11
- package/dist/addresses/polygonProxy.js +6 -6
- package/dist/generated.d.ts +45 -61
- package/dist/generated.d.ts.map +1 -1
- package/dist/leverage/deleverageExecute.d.ts +7 -1
- package/dist/leverage/deleverageExecute.d.ts.map +1 -1
- package/dist/leverage/deleverageExecute.js +11 -16
- package/dist/leverage/deleverageExecute.js.map +1 -1
- package/dist/leverage/execute.d.ts +7 -1
- package/dist/leverage/execute.d.ts.map +1 -1
- package/dist/leverage/execute.js +11 -16
- package/dist/leverage/execute.js.map +1 -1
- package/dist/views/core.d.ts +81 -1
- package/dist/views/core.d.ts.map +1 -1
- package/dist/views/core.js +81 -2
- package/dist/views/core.js.map +1 -1
- package/package.json +1 -1
- package/src/abi/full/VarlaCore.ts +55 -77
- package/src/abi/full/VarlaLiquidator.ts +1 -1
- package/src/actions/core.ts +51 -5
- package/src/actions/erc1155.ts +96 -0
- package/src/addresses/polygon.json +11 -11
- package/src/addresses/polygon.ts +11 -11
- package/src/addresses/polygonProxy.json +6 -6
- package/src/addresses/polygonProxy.ts +6 -6
- package/src/leverage/deleverageExecute.ts +19 -20
- package/src/leverage/execute.ts +19 -20
- package/src/views/core.ts +153 -3
package/src/actions/core.ts
CHANGED
|
@@ -5,6 +5,8 @@ import type { Address, PublicClient } from "viem";
|
|
|
5
5
|
import { abis } from "../generated.js";
|
|
6
6
|
import type { SimulatedTx } from "./oracle.js";
|
|
7
7
|
|
|
8
|
+
const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000" as const;
|
|
9
|
+
|
|
8
10
|
export async function prepareCoreDeposit(params: {
|
|
9
11
|
publicClient: Pick<PublicClient, "simulateContract">;
|
|
10
12
|
coreAddress: Address;
|
|
@@ -21,18 +23,50 @@ export async function prepareCoreDeposit(params: {
|
|
|
21
23
|
} as any)) as any;
|
|
22
24
|
}
|
|
23
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Withdraw deposited ERC1155 collateral from VarlaCore back to a wallet.
|
|
28
|
+
*
|
|
29
|
+
* Two call paths:
|
|
30
|
+
* - **No `recipient`** (default): calls `withdraw(ids, amounts)` — tokens sent to `msg.sender`.
|
|
31
|
+
* - **With `recipient`**: calls `withdraw(ids, amounts, destination)` — tokens sent to the
|
|
32
|
+
* specified address instead of the caller. Useful for Safe / proxy wallets or any flow
|
|
33
|
+
* where the signer and the token recipient differ.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* // Withdraw to self (default)
|
|
38
|
+
* const tx = await prepareCoreWithdraw({ publicClient, coreAddress, account, positionIds, amounts });
|
|
39
|
+
*
|
|
40
|
+
* // Withdraw to a different address
|
|
41
|
+
* const tx = await prepareCoreWithdraw({
|
|
42
|
+
* publicClient, coreAddress, account,
|
|
43
|
+
* positionIds, amounts,
|
|
44
|
+
* recipient: "0xAbc...",
|
|
45
|
+
* });
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
24
48
|
export async function prepareCoreWithdraw(params: {
|
|
25
49
|
publicClient: Pick<PublicClient, "simulateContract">;
|
|
26
50
|
coreAddress: Address;
|
|
27
51
|
account: Address;
|
|
28
52
|
positionIds: readonly bigint[];
|
|
29
53
|
amounts: readonly bigint[];
|
|
54
|
+
/**
|
|
55
|
+
* Optional destination address for the withdrawn ERC1155 tokens.
|
|
56
|
+
*
|
|
57
|
+
* When provided, calls `withdraw(positionIds, amounts, destination)`.
|
|
58
|
+
* When omitted, calls `withdraw(positionIds, amounts)` (tokens go to `msg.sender`).
|
|
59
|
+
*/
|
|
60
|
+
recipient?: Address;
|
|
30
61
|
}): Promise<SimulatedTx> {
|
|
31
62
|
return (await params.publicClient.simulateContract({
|
|
32
63
|
address: params.coreAddress,
|
|
33
64
|
abi: abis.VARLACORE_ABI,
|
|
34
65
|
functionName: "withdraw",
|
|
35
|
-
args:
|
|
66
|
+
args:
|
|
67
|
+
params.recipient !== undefined
|
|
68
|
+
? [params.positionIds, params.amounts, params.recipient]
|
|
69
|
+
: [params.positionIds, params.amounts],
|
|
36
70
|
account: params.account,
|
|
37
71
|
} as any)) as any;
|
|
38
72
|
}
|
|
@@ -42,12 +76,17 @@ export async function prepareCoreBorrow(params: {
|
|
|
42
76
|
coreAddress: Address;
|
|
43
77
|
account: Address;
|
|
44
78
|
amount: bigint;
|
|
79
|
+
outputAsset?: Address;
|
|
80
|
+
recipient?: Address;
|
|
45
81
|
}): Promise<SimulatedTx> {
|
|
82
|
+
const useRecipientPath = params.outputAsset !== undefined || params.recipient !== undefined;
|
|
46
83
|
return (await params.publicClient.simulateContract({
|
|
47
84
|
address: params.coreAddress,
|
|
48
85
|
abi: abis.VARLACORE_ABI,
|
|
49
86
|
functionName: "borrow",
|
|
50
|
-
args:
|
|
87
|
+
args: useRecipientPath
|
|
88
|
+
? [params.amount, params.outputAsset ?? ZERO_ADDRESS, params.recipient ?? params.account]
|
|
89
|
+
: [params.amount],
|
|
51
90
|
account: params.account,
|
|
52
91
|
} as any)) as any;
|
|
53
92
|
}
|
|
@@ -58,12 +97,13 @@ export async function prepareCoreBorrowWithAsset(params: {
|
|
|
58
97
|
account: Address;
|
|
59
98
|
amount: bigint;
|
|
60
99
|
outputAsset: Address;
|
|
100
|
+
recipient?: Address;
|
|
61
101
|
}): Promise<SimulatedTx> {
|
|
62
102
|
return (await params.publicClient.simulateContract({
|
|
63
103
|
address: params.coreAddress,
|
|
64
104
|
abi: abis.VARLACORE_ABI,
|
|
65
105
|
functionName: "borrow",
|
|
66
|
-
args: [params.amount, params.outputAsset],
|
|
106
|
+
args: [params.amount, params.outputAsset, params.recipient ?? params.account],
|
|
67
107
|
account: params.account,
|
|
68
108
|
} as any)) as any;
|
|
69
109
|
}
|
|
@@ -73,12 +113,17 @@ export async function prepareCoreRepay(params: {
|
|
|
73
113
|
coreAddress: Address;
|
|
74
114
|
account: Address;
|
|
75
115
|
amount: bigint;
|
|
116
|
+
inputAsset?: Address;
|
|
117
|
+
onBehalfOf?: Address;
|
|
76
118
|
}): Promise<SimulatedTx> {
|
|
119
|
+
const useOnBehalfPath = params.inputAsset !== undefined || params.onBehalfOf !== undefined;
|
|
77
120
|
return (await params.publicClient.simulateContract({
|
|
78
121
|
address: params.coreAddress,
|
|
79
122
|
abi: abis.VARLACORE_ABI,
|
|
80
123
|
functionName: "repay",
|
|
81
|
-
args:
|
|
124
|
+
args: useOnBehalfPath
|
|
125
|
+
? [params.amount, params.inputAsset ?? ZERO_ADDRESS, params.onBehalfOf ?? params.account]
|
|
126
|
+
: [params.amount],
|
|
82
127
|
account: params.account,
|
|
83
128
|
} as any)) as any;
|
|
84
129
|
}
|
|
@@ -89,12 +134,13 @@ export async function prepareCoreRepayWithAsset(params: {
|
|
|
89
134
|
account: Address;
|
|
90
135
|
amount: bigint;
|
|
91
136
|
inputAsset: Address;
|
|
137
|
+
onBehalfOf?: Address;
|
|
92
138
|
}): Promise<SimulatedTx> {
|
|
93
139
|
return (await params.publicClient.simulateContract({
|
|
94
140
|
address: params.coreAddress,
|
|
95
141
|
abi: abis.VARLACORE_ABI,
|
|
96
142
|
functionName: "repay",
|
|
97
|
-
args: [params.amount, params.inputAsset],
|
|
143
|
+
args: [params.amount, params.inputAsset, params.onBehalfOf ?? params.account],
|
|
98
144
|
account: params.account,
|
|
99
145
|
} as any)) as any;
|
|
100
146
|
}
|
package/src/actions/erc1155.ts
CHANGED
|
@@ -20,3 +20,99 @@ export async function prepareErc1155SetApprovalForAll(params: {
|
|
|
20
20
|
account: params.account,
|
|
21
21
|
} as any)) as any;
|
|
22
22
|
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Deposit a single ERC1155 position into VarlaCore by directly calling
|
|
26
|
+
* `ctf.safeTransferFrom(user, core, id, amount, "")`.
|
|
27
|
+
*
|
|
28
|
+
* This triggers VarlaCore's `onERC1155Received` hook which credits the
|
|
29
|
+
* sender (`from`) with the deposited amount — no prior `setApprovalForAll`
|
|
30
|
+
* to Core is required since the caller is initiating the transfer themselves.
|
|
31
|
+
*
|
|
32
|
+
* Use this as a drop-in alternative to `prepareCoreDeposit` when the user
|
|
33
|
+
* prefers the ERC1155-push pattern (e.g. in single-token flows or when
|
|
34
|
+
* building atomic Safe multisend batches where approval is undesirable).
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```ts
|
|
38
|
+
* import { prepareCoreDepositViaSafeTransfer } from "@varla/sdk/actions";
|
|
39
|
+
*
|
|
40
|
+
* const tx = await prepareCoreDepositViaSafeTransfer({
|
|
41
|
+
* publicClient,
|
|
42
|
+
* ctfAddress,
|
|
43
|
+
* coreAddress,
|
|
44
|
+
* account: userAddress,
|
|
45
|
+
* positionId: BigInt(posId),
|
|
46
|
+
* amount: 100_000_000n, // 100 USDC (6 decimals)
|
|
47
|
+
* });
|
|
48
|
+
* await walletClient.writeContract(tx.request);
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export async function prepareCoreDepositViaSafeTransfer(params: {
|
|
52
|
+
publicClient: Pick<PublicClient, "simulateContract">;
|
|
53
|
+
/** Address of the ERC1155 positions token (Polymarket CTF). */
|
|
54
|
+
ctfAddress: Address;
|
|
55
|
+
/** Address of VarlaCore (the transfer recipient). */
|
|
56
|
+
coreAddress: Address;
|
|
57
|
+
account: Address;
|
|
58
|
+
positionId: bigint;
|
|
59
|
+
amount: bigint;
|
|
60
|
+
}): Promise<SimulatedTx> {
|
|
61
|
+
return (await params.publicClient.simulateContract({
|
|
62
|
+
address: params.ctfAddress,
|
|
63
|
+
abi: erc1155Abi,
|
|
64
|
+
functionName: "safeTransferFrom",
|
|
65
|
+
args: [params.account, params.coreAddress, params.positionId, params.amount, "0x"],
|
|
66
|
+
account: params.account,
|
|
67
|
+
} as any)) as any;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Deposit multiple ERC1155 positions into VarlaCore in a single call by using
|
|
72
|
+
* `ctf.safeBatchTransferFrom(user, core, ids, amounts, "")`.
|
|
73
|
+
*
|
|
74
|
+
* This triggers VarlaCore's `onERC1155BatchReceived` hook which credits the
|
|
75
|
+
* sender (`from`) with each transferred amount. No prior `setApprovalForAll`
|
|
76
|
+
* to Core is needed.
|
|
77
|
+
*
|
|
78
|
+
* Prefer this over multiple `prepareCoreDepositViaSafeTransfer` calls when
|
|
79
|
+
* depositing several positions atomically (single tx, lower gas).
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```ts
|
|
83
|
+
* import { prepareCoreDepositViaSafeBatchTransfer } from "@varla/sdk/actions";
|
|
84
|
+
*
|
|
85
|
+
* const tx = await prepareCoreDepositViaSafeBatchTransfer({
|
|
86
|
+
* publicClient,
|
|
87
|
+
* ctfAddress,
|
|
88
|
+
* coreAddress,
|
|
89
|
+
* account: userAddress,
|
|
90
|
+
* positionIds: [BigInt(yesId), BigInt(noId)],
|
|
91
|
+
* amounts: [50_000_000n, 50_000_000n],
|
|
92
|
+
* });
|
|
93
|
+
* await walletClient.writeContract(tx.request);
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
export async function prepareCoreDepositViaSafeBatchTransfer(params: {
|
|
97
|
+
publicClient: Pick<PublicClient, "simulateContract">;
|
|
98
|
+
/** Address of the ERC1155 positions token (Polymarket CTF). */
|
|
99
|
+
ctfAddress: Address;
|
|
100
|
+
/** Address of VarlaCore (the transfer recipient). */
|
|
101
|
+
coreAddress: Address;
|
|
102
|
+
account: Address;
|
|
103
|
+
positionIds: readonly bigint[];
|
|
104
|
+
amounts: readonly bigint[];
|
|
105
|
+
}): Promise<SimulatedTx> {
|
|
106
|
+
if (params.positionIds.length !== params.amounts.length) {
|
|
107
|
+
throw new Error(
|
|
108
|
+
`prepareCoreDepositViaSafeBatchTransfer: positionIds.length (${params.positionIds.length}) must equal amounts.length (${params.amounts.length})`,
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
return (await params.publicClient.simulateContract({
|
|
112
|
+
address: params.ctfAddress,
|
|
113
|
+
abi: erc1155Abi,
|
|
114
|
+
functionName: "safeBatchTransferFrom",
|
|
115
|
+
args: [params.account, params.coreAddress, params.positionIds, params.amounts, "0x"],
|
|
116
|
+
account: params.account,
|
|
117
|
+
} as any)) as any;
|
|
118
|
+
}
|
|
@@ -3,16 +3,16 @@
|
|
|
3
3
|
"generatedAt": "",
|
|
4
4
|
"deploymentsDir": "polygon",
|
|
5
5
|
"contracts": {
|
|
6
|
-
"VarlaAccessManager": "
|
|
7
|
-
"VarlaOracle": "
|
|
8
|
-
"VarlaCore": "
|
|
9
|
-
"VarlaPool": "
|
|
10
|
-
"OracleUpdaterRouter": "
|
|
11
|
-
"VarlaInterestRateStrategy": "
|
|
12
|
-
"VarlaProxyAdmin": "
|
|
13
|
-
"VarlaLiquidator": "
|
|
14
|
-
"VarlaMergeLiquidator": "
|
|
15
|
-
"VarlaConvertLiquidator": "
|
|
16
|
-
"PolymarketCtfAdapter": "
|
|
6
|
+
"VarlaAccessManager": "0xEC4CBe73cFA6846B6772341e199289F7A4f20e7e",
|
|
7
|
+
"VarlaOracle": "0xA63c6ebD3a0C6990D16Ea94D957c2Ad8D3c7Dd10",
|
|
8
|
+
"VarlaCore": "0xc1c7720Eb3563630aA77be561cD0B58F1Fa280F6",
|
|
9
|
+
"VarlaPool": "0xc939CC89340E22bDf33df82A55118b19d4A11Bc2",
|
|
10
|
+
"OracleUpdaterRouter": "0x59389217DEB847b3747767b2D7f56ffec43E9c72",
|
|
11
|
+
"VarlaInterestRateStrategy": "0x62cf2ab7346b5bA86faaa302d1E39908525166dB",
|
|
12
|
+
"VarlaProxyAdmin": "0xf06B99237d2A53c6026ff5E3723417E6dEDcA651",
|
|
13
|
+
"VarlaLiquidator": "0xd7760D42661b8A559A61351873E0e006985F0d75",
|
|
14
|
+
"VarlaMergeLiquidator": "0x5fA44Ba97470ADaDc97cb7F3ce64baceeE37f97a",
|
|
15
|
+
"VarlaConvertLiquidator": "0xBA802DF5e8258636738A28d27573203B32D2120A",
|
|
16
|
+
"PolymarketCtfAdapter": "0x66Ed3cf23719eb9111966AF6D6842F6548165313"
|
|
17
17
|
}
|
|
18
18
|
}
|
package/src/addresses/polygon.ts
CHANGED
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
import type { AddressBook } from "../types";
|
|
3
3
|
|
|
4
4
|
export const polygon: AddressBook = {
|
|
5
|
-
accessManager: "
|
|
6
|
-
oracle: "
|
|
7
|
-
core: "
|
|
8
|
-
pool: "
|
|
9
|
-
oracleUpdaterRouter: "
|
|
10
|
-
interestRateStrategy: "
|
|
11
|
-
proxyAdmin: "
|
|
12
|
-
liquidator: "
|
|
13
|
-
mergeLiquidator: "
|
|
14
|
-
convertLiquidator: "
|
|
15
|
-
polymarketCtfAdapter: "
|
|
5
|
+
accessManager: "0xEC4CBe73cFA6846B6772341e199289F7A4f20e7e",
|
|
6
|
+
oracle: "0xA63c6ebD3a0C6990D16Ea94D957c2Ad8D3c7Dd10",
|
|
7
|
+
core: "0xc1c7720Eb3563630aA77be561cD0B58F1Fa280F6",
|
|
8
|
+
pool: "0xc939CC89340E22bDf33df82A55118b19d4A11Bc2",
|
|
9
|
+
oracleUpdaterRouter: "0x59389217DEB847b3747767b2D7f56ffec43E9c72",
|
|
10
|
+
interestRateStrategy: "0x62cf2ab7346b5bA86faaa302d1E39908525166dB",
|
|
11
|
+
proxyAdmin: "0xf06B99237d2A53c6026ff5E3723417E6dEDcA651",
|
|
12
|
+
liquidator: "0xd7760D42661b8A559A61351873E0e006985F0d75",
|
|
13
|
+
mergeLiquidator: "0x5fA44Ba97470ADaDc97cb7F3ce64baceeE37f97a",
|
|
14
|
+
convertLiquidator: "0xBA802DF5e8258636738A28d27573203B32D2120A",
|
|
15
|
+
polymarketCtfAdapter: "0x66Ed3cf23719eb9111966AF6D6842F6548165313",
|
|
16
16
|
};
|
|
17
17
|
|
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
"contracts": {
|
|
6
6
|
"VarlaAccessManager": "0x5069d899bA3EBC4e12aB357F44B1DA3b0D0395f4",
|
|
7
7
|
"VarlaOracle": "0x14e102a52474f569eB6C536a1bb15b9F69c5ba8f",
|
|
8
|
-
"VarlaCore": "
|
|
9
|
-
"VarlaPool": "
|
|
8
|
+
"VarlaCore": "0xB7e45923a4B21793Bae7Bd445fdd7318B0fF1409",
|
|
9
|
+
"VarlaPool": "0x0845B5b2cF295C77eBB23347706A30448bEf9aF2",
|
|
10
10
|
"OracleUpdaterRouter": "0x3E1e6B54626D486b844C94e2385773b018fEB891",
|
|
11
|
-
"VarlaInterestRateStrategy": "
|
|
11
|
+
"VarlaInterestRateStrategy": "0x3Ae3a0B358a53aF835A924F4799c91943206e3d1",
|
|
12
12
|
"VarlaProxyAdmin": "0x084aBfA2f32A53741DDd12D3166dA1318e7d73f7",
|
|
13
|
-
"VarlaLiquidator": "
|
|
14
|
-
"VarlaMergeLiquidator": "
|
|
15
|
-
"VarlaConvertLiquidator": "
|
|
13
|
+
"VarlaLiquidator": "0x0f031BFbfFB08C3f844b8e59BAd9975CBec194b5",
|
|
14
|
+
"VarlaMergeLiquidator": "0x573A7bD3117c9D8EA1913c2Ccbdbf29E86EE4621",
|
|
15
|
+
"VarlaConvertLiquidator": "0xc1ba05218Fb56b5e31D34b3bb772fa57F1eDC7e4",
|
|
16
16
|
"PolymarketCtfAdapter": "0x86B39800540D2C42eF1E34DF69117CB34F35a341"
|
|
17
17
|
}
|
|
18
18
|
}
|
|
@@ -4,14 +4,14 @@ import type { AddressBook } from "../types";
|
|
|
4
4
|
export const polygonProxy: AddressBook = {
|
|
5
5
|
accessManager: "0x5069d899bA3EBC4e12aB357F44B1DA3b0D0395f4",
|
|
6
6
|
oracle: "0x14e102a52474f569eB6C536a1bb15b9F69c5ba8f",
|
|
7
|
-
core: "
|
|
8
|
-
pool: "
|
|
7
|
+
core: "0xB7e45923a4B21793Bae7Bd445fdd7318B0fF1409",
|
|
8
|
+
pool: "0x0845B5b2cF295C77eBB23347706A30448bEf9aF2",
|
|
9
9
|
oracleUpdaterRouter: "0x3E1e6B54626D486b844C94e2385773b018fEB891",
|
|
10
|
-
interestRateStrategy: "
|
|
10
|
+
interestRateStrategy: "0x3Ae3a0B358a53aF835A924F4799c91943206e3d1",
|
|
11
11
|
proxyAdmin: "0x084aBfA2f32A53741DDd12D3166dA1318e7d73f7",
|
|
12
|
-
liquidator: "
|
|
13
|
-
mergeLiquidator: "
|
|
14
|
-
convertLiquidator: "
|
|
12
|
+
liquidator: "0x0f031BFbfFB08C3f844b8e59BAd9975CBec194b5",
|
|
13
|
+
mergeLiquidator: "0x573A7bD3117c9D8EA1913c2Ccbdbf29E86EE4621",
|
|
14
|
+
convertLiquidator: "0xc1ba05218Fb56b5e31D34b3bb772fa57F1eDC7e4",
|
|
15
15
|
polymarketCtfAdapter: "0x86B39800540D2C42eF1E34DF69117CB34F35a341",
|
|
16
16
|
};
|
|
17
17
|
|
|
@@ -9,11 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
import type { Address, Hash, PublicClient, WalletClient } from "viem";
|
|
11
11
|
|
|
12
|
-
import {
|
|
13
|
-
prepareCoreRepay,
|
|
14
|
-
prepareCoreRepayWithAsset,
|
|
15
|
-
prepareCoreWithdraw,
|
|
16
|
-
} from "../actions/core.js";
|
|
12
|
+
import { prepareCoreRepay, prepareCoreWithdraw } from "../actions/core.js";
|
|
17
13
|
import { sendTx } from "../actions/tx.js";
|
|
18
14
|
import type { ReceiptRetryOptions } from "./receipt.js";
|
|
19
15
|
import { waitForReceiptWithRetry } from "./receipt.js";
|
|
@@ -39,10 +35,16 @@ export type RunDeleverageLoopParams = {
|
|
|
39
35
|
/**
|
|
40
36
|
* Optional repay settlement asset for core repay steps.
|
|
41
37
|
*
|
|
42
|
-
* When provided, repay steps call `VarlaCore.repay(amount, inputAsset)`.
|
|
38
|
+
* When provided, repay steps call `VarlaCore.repay(amount, inputAsset, onBehalfOf)`.
|
|
43
39
|
* When omitted, repay steps call the default `VarlaCore.repay(amount)`.
|
|
44
40
|
*/
|
|
45
41
|
inputAsset?: Address;
|
|
42
|
+
/**
|
|
43
|
+
* Optional borrower whose debt should be repaid by `account`.
|
|
44
|
+
*
|
|
45
|
+
* Defaults to `account`.
|
|
46
|
+
*/
|
|
47
|
+
repayOnBehalfOf?: Address;
|
|
46
48
|
/** Off-chain sell callback. */
|
|
47
49
|
onSellStep: (step: Extract<DeleverageStep, { kind: "sell" }>) => Promise<SellResult>;
|
|
48
50
|
onProgress?: OnDeleverageProgress;
|
|
@@ -139,6 +141,7 @@ export async function runDeleverageLoop(
|
|
|
139
141
|
coreAddress,
|
|
140
142
|
account,
|
|
141
143
|
inputAsset,
|
|
144
|
+
repayOnBehalfOf,
|
|
142
145
|
onSellStep,
|
|
143
146
|
onProgress,
|
|
144
147
|
confirmations = 1,
|
|
@@ -207,21 +210,17 @@ export async function runDeleverageLoop(
|
|
|
207
210
|
if (step.kind === "repay") {
|
|
208
211
|
const repayAmount = lastSellActualCollateral ?? step.collateralAmount;
|
|
209
212
|
lastSellActualCollateral = undefined;
|
|
213
|
+
const onBehalfOf = repayOnBehalfOf ?? account;
|
|
214
|
+
const useOnBehalfPath =
|
|
215
|
+
inputAsset !== undefined || onBehalfOf.toLowerCase() !== account.toLowerCase();
|
|
210
216
|
|
|
211
|
-
const sim =
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
})
|
|
219
|
-
: await prepareCoreRepay({
|
|
220
|
-
publicClient: publicClient as any,
|
|
221
|
-
coreAddress,
|
|
222
|
-
account,
|
|
223
|
-
amount: repayAmount,
|
|
224
|
-
});
|
|
217
|
+
const sim = await prepareCoreRepay({
|
|
218
|
+
publicClient: publicClient as any,
|
|
219
|
+
coreAddress,
|
|
220
|
+
account,
|
|
221
|
+
amount: repayAmount,
|
|
222
|
+
...(useOnBehalfPath ? { inputAsset, onBehalfOf } : {}),
|
|
223
|
+
});
|
|
225
224
|
const hash = await sendTx({ walletClient: walletClient as any, request: sim.request });
|
|
226
225
|
await waitForReceiptWithRetry({ publicClient, hash, confirmations, retry: receiptRetry });
|
|
227
226
|
|
package/src/leverage/execute.ts
CHANGED
|
@@ -10,11 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
import type { Address, Hash, PublicClient, WalletClient } from "viem";
|
|
12
12
|
|
|
13
|
-
import {
|
|
14
|
-
prepareCoreBorrow,
|
|
15
|
-
prepareCoreBorrowWithAsset,
|
|
16
|
-
prepareCoreDeposit,
|
|
17
|
-
} from "../actions/core.js";
|
|
13
|
+
import { prepareCoreBorrow, prepareCoreDeposit } from "../actions/core.js";
|
|
18
14
|
import { sendTx } from "../actions/tx.js";
|
|
19
15
|
import type { ReceiptRetryOptions } from "./receipt.js";
|
|
20
16
|
import { waitForReceiptWithRetry } from "./receipt.js";
|
|
@@ -44,10 +40,16 @@ export type RunLeverageLoopParams = {
|
|
|
44
40
|
/**
|
|
45
41
|
* Optional borrow output asset for core borrow steps.
|
|
46
42
|
*
|
|
47
|
-
* When provided, borrow steps call `VarlaCore.borrow(amount, outputAsset)`.
|
|
43
|
+
* When provided, borrow steps call `VarlaCore.borrow(amount, outputAsset, recipient)`.
|
|
48
44
|
* When omitted, borrow steps call the default `VarlaCore.borrow(amount)`.
|
|
49
45
|
*/
|
|
50
46
|
outputAsset?: Address;
|
|
47
|
+
/**
|
|
48
|
+
* Optional recipient for borrow proceeds.
|
|
49
|
+
*
|
|
50
|
+
* Defaults to `account`. Debt remains on `account`.
|
|
51
|
+
*/
|
|
52
|
+
borrowRecipient?: Address;
|
|
51
53
|
/**
|
|
52
54
|
* Consumer-provided callback for off-chain token acquisition.
|
|
53
55
|
*
|
|
@@ -166,6 +168,7 @@ export async function runLeverageLoop(
|
|
|
166
168
|
coreAddress,
|
|
167
169
|
account,
|
|
168
170
|
outputAsset,
|
|
171
|
+
borrowRecipient,
|
|
169
172
|
onBuyStep,
|
|
170
173
|
onProgress,
|
|
171
174
|
confirmations = 1,
|
|
@@ -235,20 +238,16 @@ export async function runLeverageLoop(
|
|
|
235
238
|
}
|
|
236
239
|
|
|
237
240
|
if (step.kind === "borrow") {
|
|
238
|
-
const
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
coreAddress,
|
|
249
|
-
account,
|
|
250
|
-
amount: step.collateralAmount,
|
|
251
|
-
});
|
|
241
|
+
const recipient = borrowRecipient ?? account;
|
|
242
|
+
const useRecipientPath =
|
|
243
|
+
outputAsset !== undefined || recipient.toLowerCase() !== account.toLowerCase();
|
|
244
|
+
const sim = await prepareCoreBorrow({
|
|
245
|
+
publicClient: publicClient as any,
|
|
246
|
+
coreAddress,
|
|
247
|
+
account,
|
|
248
|
+
amount: step.collateralAmount,
|
|
249
|
+
...(useRecipientPath ? { outputAsset, recipient } : {}),
|
|
250
|
+
});
|
|
252
251
|
|
|
253
252
|
const hash = await sendTx({ walletClient: walletClient as any, request: sim.request });
|
|
254
253
|
await waitForReceiptWithRetry({ publicClient, hash, confirmations, retry: receiptRetry });
|
package/src/views/core.ts
CHANGED
|
@@ -196,6 +196,150 @@ export async function previewCoreDeposit(params: {
|
|
|
196
196
|
};
|
|
197
197
|
}
|
|
198
198
|
|
|
199
|
+
// ---------------------------------------------------------------------------
|
|
200
|
+
// Withdraw pre-flight (previewCoreWithdraw)
|
|
201
|
+
// ---------------------------------------------------------------------------
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Reason a collateral withdrawal would be rejected for a specific position.
|
|
205
|
+
*
|
|
206
|
+
* - `"zero-amount"` — caller passed `amount === 0n`.
|
|
207
|
+
* - `"insufficient-balance"` — user's deposited balance is below the requested amount.
|
|
208
|
+
*/
|
|
209
|
+
export type WithdrawBlockReason = "zero-amount" | "insufficient-balance";
|
|
210
|
+
|
|
211
|
+
export type PreviewCoreWithdrawItem = {
|
|
212
|
+
positionId: bigint;
|
|
213
|
+
amount: bigint;
|
|
214
|
+
/** Current deposited balance of the user for this position. */
|
|
215
|
+
balance: bigint;
|
|
216
|
+
/** `true` when this position passes the pre-flight balance check. */
|
|
217
|
+
ok: boolean;
|
|
218
|
+
/** Present only when `ok === false`. */
|
|
219
|
+
reason?: WithdrawBlockReason;
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
export type PreviewCoreWithdraw = {
|
|
223
|
+
/**
|
|
224
|
+
* `true` only when every position passes the balance check AND the user either
|
|
225
|
+
* has no outstanding debt or has sufficient health factor to absorb the withdrawal.
|
|
226
|
+
*
|
|
227
|
+
* When `hasDeb === true`, always simulate the on-chain call or check HF separately
|
|
228
|
+
* before submitting — this preview cannot compute the exact post-withdraw HF
|
|
229
|
+
* without oracle price data.
|
|
230
|
+
*/
|
|
231
|
+
canWithdraw: boolean;
|
|
232
|
+
/** Per-position results aligned to input order. */
|
|
233
|
+
items: PreviewCoreWithdrawItem[];
|
|
234
|
+
/** `true` when the user has any outstanding debt. Withdrawing while indebted
|
|
235
|
+
* may reduce the health factor below the liquidation threshold. */
|
|
236
|
+
hasDebt: boolean;
|
|
237
|
+
/** Current health factor (WAD). `0` when the user has no debt. */
|
|
238
|
+
healthFactor: bigint;
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Pre-flight check that mirrors VarlaCore.withdraw() balance validation.
|
|
243
|
+
*
|
|
244
|
+
* Checks (per position):
|
|
245
|
+
* 1. `amount > 0`
|
|
246
|
+
* 2. `core.positionBalances(user, id) >= amount`
|
|
247
|
+
*
|
|
248
|
+
* Account-level:
|
|
249
|
+
* - Whether the user currently has debt (`debt > 0`).
|
|
250
|
+
*
|
|
251
|
+
* **Important**: this function cannot predict the post-withdraw health factor
|
|
252
|
+
* without live oracle prices. When `hasDebt === true`, always double-check
|
|
253
|
+
* the HF with `readHealthFactor` or simulate the transaction before submitting.
|
|
254
|
+
*
|
|
255
|
+
* @example
|
|
256
|
+
* ```ts
|
|
257
|
+
* import { previewCoreWithdraw } from "@varla/sdk/views";
|
|
258
|
+
*
|
|
259
|
+
* const preview = await previewCoreWithdraw({
|
|
260
|
+
* core,
|
|
261
|
+
* user: "0x...",
|
|
262
|
+
* positionIds: [yesId],
|
|
263
|
+
* amounts: [50_000_000n],
|
|
264
|
+
* });
|
|
265
|
+
*
|
|
266
|
+
* if (!preview.canWithdraw) {
|
|
267
|
+
* for (const item of preview.items) {
|
|
268
|
+
* if (!item.ok) console.log(`Position ${item.positionId}: ${item.reason}`);
|
|
269
|
+
* }
|
|
270
|
+
* if (preview.hasDebt) console.log("User has debt — check HF before withdrawing");
|
|
271
|
+
* }
|
|
272
|
+
* ```
|
|
273
|
+
*/
|
|
274
|
+
// wraps: VarlaCore.positionBalances,VarlaCore.getDebt,VarlaCore.getHealthFactor
|
|
275
|
+
export async function previewCoreWithdraw(params: {
|
|
276
|
+
core: {
|
|
277
|
+
read: {
|
|
278
|
+
positionBalances: (args: readonly [Address, bigint]) => Promise<bigint>;
|
|
279
|
+
getDebt: (args: readonly [Address]) => Promise<bigint>;
|
|
280
|
+
getHealthFactor: (args: readonly [Address]) => Promise<unknown>;
|
|
281
|
+
};
|
|
282
|
+
};
|
|
283
|
+
user: Address;
|
|
284
|
+
positionIds: readonly bigint[];
|
|
285
|
+
amounts: readonly bigint[];
|
|
286
|
+
}): Promise<PreviewCoreWithdraw> {
|
|
287
|
+
const { core, user, positionIds, amounts } = params;
|
|
288
|
+
|
|
289
|
+
if (positionIds.length !== amounts.length) {
|
|
290
|
+
throw new Error("previewCoreWithdraw: positionIds and amounts must have the same length");
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Fetch all balances and account debt in parallel.
|
|
294
|
+
const [balances, debt, hfRaw] = await Promise.all([
|
|
295
|
+
Promise.all(positionIds.map((pid) => core.read.positionBalances([user, pid]))),
|
|
296
|
+
core.read.getDebt([user]),
|
|
297
|
+
core.read.getHealthFactor([user]),
|
|
298
|
+
]);
|
|
299
|
+
|
|
300
|
+
// Extract health factor from the tuple returned by VarlaCore.getHealthFactor.
|
|
301
|
+
const hfAny = hfRaw as any;
|
|
302
|
+
const healthFactor: bigint =
|
|
303
|
+
typeof hfAny === "bigint"
|
|
304
|
+
? hfAny
|
|
305
|
+
: typeof hfAny?.healthFactor === "bigint"
|
|
306
|
+
? hfAny.healthFactor
|
|
307
|
+
: (hfAny?.[0] ?? 0n);
|
|
308
|
+
|
|
309
|
+
// Per-position checks.
|
|
310
|
+
const items: PreviewCoreWithdrawItem[] = [];
|
|
311
|
+
let allItemsOk = true;
|
|
312
|
+
|
|
313
|
+
for (let i = 0; i < positionIds.length; i++) {
|
|
314
|
+
const pid = positionIds[i]!;
|
|
315
|
+
const amount = amounts[i]!;
|
|
316
|
+
const balance = balances[i]!;
|
|
317
|
+
|
|
318
|
+
let ok = true;
|
|
319
|
+
let reason: WithdrawBlockReason | undefined;
|
|
320
|
+
|
|
321
|
+
if (amount === 0n) {
|
|
322
|
+
ok = false;
|
|
323
|
+
reason = "zero-amount";
|
|
324
|
+
} else if (balance < amount) {
|
|
325
|
+
ok = false;
|
|
326
|
+
reason = "insufficient-balance";
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if (!ok) allItemsOk = false;
|
|
330
|
+
items.push(
|
|
331
|
+
reason !== undefined
|
|
332
|
+
? { positionId: pid, amount, balance, ok, reason }
|
|
333
|
+
: { positionId: pid, amount, balance, ok },
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const hasDebt = debt > 0n;
|
|
338
|
+
const canWithdraw = allItemsOk;
|
|
339
|
+
|
|
340
|
+
return { canWithdraw, items, hasDebt, healthFactor };
|
|
341
|
+
}
|
|
342
|
+
|
|
199
343
|
export type ReadAccountSnapshot = {
|
|
200
344
|
portfolioValue: bigint;
|
|
201
345
|
collateralValue: bigint;
|
|
@@ -513,12 +657,18 @@ export async function readBorrowerState(params: {
|
|
|
513
657
|
return { user: params.user, scaledDebt, isBorrower, isLiquidatable };
|
|
514
658
|
}
|
|
515
659
|
|
|
516
|
-
// wraps: VarlaCore.
|
|
660
|
+
// wraps: VarlaCore.getAccountSummary
|
|
517
661
|
export async function readPortfolioValue(params: {
|
|
518
|
-
core: {
|
|
662
|
+
core: {
|
|
663
|
+
read: {
|
|
664
|
+
getAccountSummary: (
|
|
665
|
+
args: readonly [Address],
|
|
666
|
+
) => Promise<readonly [bigint, bigint, bigint, bigint, bigint]>;
|
|
667
|
+
};
|
|
668
|
+
};
|
|
519
669
|
user: Address;
|
|
520
670
|
}): Promise<ReadPortfolioValue> {
|
|
521
|
-
const portfolioValue = await params.core.read.
|
|
671
|
+
const [portfolioValue] = await params.core.read.getAccountSummary([params.user]);
|
|
522
672
|
return { user: params.user, portfolioValue };
|
|
523
673
|
}
|
|
524
674
|
|