Skip to content

Commit a25a97e

Browse files
authored
Merge pull request #46 from szhygulin/refactor/reduce-size
refactor: dedup token-meta + approval-chain boilerplate
2 parents 2a225fd + 88b06cd commit a25a97e

8 files changed

Lines changed: 76 additions & 149 deletions

File tree

src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,10 @@ import { getPortfolioSummaryInput } from "./modules/portfolio/schemas.js";
4343
import { getSwapQuote, prepareSwap } from "./modules/swap/index.js";
4444
import { getSwapQuoteInput, prepareSwapInput } from "./modules/swap/schemas.js";
4545

46+
import { getSessionStatus as getLedgerStatus } from "./signing/session.js";
4647
import {
4748
pairLedgerLive,
4849
pairLedgerTron,
49-
getLedgerStatus,
5050
prepareAaveSupply,
5151
prepareAaveWithdraw,
5252
prepareAaveBorrow,

src/modules/compound/actions.ts

Lines changed: 8 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { encodeFunctionData, parseUnits, maxUint256 } from "viem";
22
import { cometAbi } from "../../abis/compound-comet.js";
3-
import { erc20Abi } from "../../abis/erc20.js";
43
import { getClient } from "../../data/rpc.js";
5-
import { buildApprovalTx, resolveApprovalCap } from "../shared/approval.js";
4+
import { buildApprovalTx, chainApproval, resolveApprovalCap } from "../shared/approval.js";
5+
import { resolveTokenMeta } from "../shared/token-meta.js";
66
import type {
77
PrepareCompoundSupplyArgs,
88
PrepareCompoundWithdrawArgs,
@@ -11,21 +11,6 @@ import type {
1111
} from "./schemas.js";
1212
import type { SupportedChain, UnsignedTx } from "../../types/index.js";
1313

14-
async function resolveMeta(
15-
chain: SupportedChain,
16-
asset: `0x${string}`
17-
): Promise<{ decimals: number; symbol: string }> {
18-
const client = getClient(chain);
19-
const [decimals, symbol] = await client.multicall({
20-
contracts: [
21-
{ address: asset, abi: erc20Abi, functionName: "decimals" },
22-
{ address: asset, abi: erc20Abi, functionName: "symbol" },
23-
],
24-
allowFailure: false,
25-
});
26-
return { decimals: Number(decimals), symbol: symbol as string };
27-
}
28-
2914
async function resolveBaseToken(
3015
chain: SupportedChain,
3116
market: `0x${string}`
@@ -76,7 +61,7 @@ export async function buildCompoundSupply(p: PrepareCompoundSupplyArgs): Promise
7661
const asset = p.asset as `0x${string}`;
7762
const wallet = p.wallet as `0x${string}`;
7863
await assertCometActionAllowed(chain, market, "supply");
79-
const meta = await resolveMeta(chain, asset);
64+
const meta = await resolveTokenMeta(chain, asset);
8065
const amountWei = parseUnits(p.amount, meta.decimals);
8166
const { approvalAmount, display } = resolveApprovalCap(
8267
p.approvalCap,
@@ -107,13 +92,7 @@ export async function buildCompoundSupply(p: PrepareCompoundSupplyArgs): Promise
10792
description: `Supply ${p.amount} ${meta.symbol} to Compound V3 ${market} on ${chain}`,
10893
decoded: { functionName: "supply", args: { asset, amount: p.amount, market } },
10994
};
110-
if (approval) {
111-
let tail = approval;
112-
while (tail.next) tail = tail.next;
113-
tail.next = supplyTx;
114-
return approval;
115-
}
116-
return supplyTx;
95+
return chainApproval(approval, supplyTx);
11796
}
11897

11998
export async function buildCompoundWithdraw(p: PrepareCompoundWithdrawArgs): Promise<UnsignedTx> {
@@ -122,7 +101,7 @@ export async function buildCompoundWithdraw(p: PrepareCompoundWithdrawArgs): Pro
122101
const asset = p.asset as `0x${string}`;
123102
const wallet = p.wallet as `0x${string}`;
124103
await assertCometActionAllowed(chain, market, "withdraw");
125-
const meta = await resolveMeta(chain, asset);
104+
const meta = await resolveTokenMeta(chain, asset);
126105
const amountWei = p.amount === "max" ? maxUint256 : parseUnits(p.amount, meta.decimals);
127106
return {
128107
chain,
@@ -146,7 +125,7 @@ export async function buildCompoundBorrow(p: PrepareCompoundBorrowArgs): Promise
146125
const wallet = p.wallet as `0x${string}`;
147126
await assertCometActionAllowed(chain, market, "withdraw");
148127
const baseToken = await resolveBaseToken(chain, market);
149-
const meta = await resolveMeta(chain, baseToken);
128+
const meta = await resolveTokenMeta(chain, baseToken);
150129
const amountWei = parseUnits(p.amount, meta.decimals);
151130
return {
152131
chain,
@@ -170,7 +149,7 @@ export async function buildCompoundRepay(p: PrepareCompoundRepayArgs): Promise<U
170149
const wallet = p.wallet as `0x${string}`;
171150
await assertCometActionAllowed(chain, market, "supply");
172151
const baseToken = await resolveBaseToken(chain, market);
173-
const meta = await resolveMeta(chain, baseToken);
152+
const meta = await resolveTokenMeta(chain, baseToken);
174153
const amountWei = p.amount === "max" ? maxUint256 : parseUnits(p.amount, meta.decimals);
175154
let approval: UnsignedTx | null = null;
176155
if (amountWei !== maxUint256) {
@@ -204,11 +183,5 @@ export async function buildCompoundRepay(p: PrepareCompoundRepayArgs): Promise<U
204183
description: `Repay ${p.amount === "max" ? "all" : p.amount} ${meta.symbol} on Compound V3 ${market} on ${chain}`,
205184
decoded: { functionName: "supply(base)", args: { asset: baseToken, amount: p.amount, market } },
206185
};
207-
if (approval) {
208-
let tail = approval;
209-
while (tail.next) tail = tail.next;
210-
tail.next = repayTx;
211-
return approval;
212-
}
213-
return repayTx;
186+
return chainApproval(approval, repayTx);
214187
}

src/modules/execution/index.ts

Lines changed: 7 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import {
55
requestSendTransaction,
66
getConnectedAccounts,
77
} from "../../signing/walletconnect.js";
8-
import { getSessionStatus } from "../../signing/session.js";
98
import {
109
consumeHandle,
1110
retireHandle,
@@ -31,6 +30,7 @@ import {
3130
} from "../../signing/verification.js";
3231
import { getClient, verifyChainId } from "../../data/rpc.js";
3332
import { erc20Abi } from "../../abis/erc20.js";
33+
import { resolveTokenMeta } from "../shared/token-meta.js";
3434
import { simulateTx } from "../simulation/index.js";
3535
import {
3636
buildAaveSupply,
@@ -133,25 +133,6 @@ export async function pairLedgerTron(args: PairLedgerTronArgs = {}): Promise<{
133133
};
134134
}
135135

136-
export async function getLedgerStatus() {
137-
return getSessionStatus();
138-
}
139-
140-
async function resolveAssetMeta(
141-
chain: SupportedChain,
142-
asset: `0x${string}`
143-
): Promise<{ decimals: number; symbol: string }> {
144-
const client = getClient(chain);
145-
const [decimals, symbol] = await client.multicall({
146-
contracts: [
147-
{ address: asset, abi: erc20Abi, functionName: "decimals" },
148-
{ address: asset, abi: erc20Abi, functionName: "symbol" },
149-
],
150-
allowFailure: false,
151-
});
152-
return { decimals: Number(decimals), symbol: symbol as string };
153-
}
154-
155136
/** Attach eth_call simulation result, gas estimate, and USD cost. */
156137
async function enrichTx(tx: UnsignedTx): Promise<UnsignedTx> {
157138
const client = getClient(tx.chain);
@@ -195,7 +176,7 @@ async function enrichTx(tx: UnsignedTx): Promise<UnsignedTx> {
195176
// ----- Aave preparation handlers -----
196177

197178
export async function prepareAaveSupply(args: PrepareAaveSupplyArgs): Promise<UnsignedTx> {
198-
const meta = await resolveAssetMeta(args.chain as SupportedChain, args.asset as `0x${string}`);
179+
const meta = await resolveTokenMeta(args.chain as SupportedChain, args.asset as `0x${string}`);
199180
return enrichTx(
200181
await buildAaveSupply({
201182
wallet: args.wallet as `0x${string}`,
@@ -210,7 +191,7 @@ export async function prepareAaveSupply(args: PrepareAaveSupplyArgs): Promise<Un
210191
}
211192

212193
export async function prepareAaveWithdraw(args: PrepareAaveWithdrawArgs): Promise<UnsignedTx> {
213-
const meta = await resolveAssetMeta(args.chain as SupportedChain, args.asset as `0x${string}`);
194+
const meta = await resolveTokenMeta(args.chain as SupportedChain, args.asset as `0x${string}`);
214195
return enrichTx(
215196
await buildAaveWithdraw({
216197
wallet: args.wallet as `0x${string}`,
@@ -224,7 +205,7 @@ export async function prepareAaveWithdraw(args: PrepareAaveWithdrawArgs): Promis
224205
}
225206

226207
export async function prepareAaveBorrow(args: PrepareAaveBorrowArgs): Promise<UnsignedTx> {
227-
const meta = await resolveAssetMeta(args.chain as SupportedChain, args.asset as `0x${string}`);
208+
const meta = await resolveTokenMeta(args.chain as SupportedChain, args.asset as `0x${string}`);
228209
return enrichTx(
229210
await buildAaveBorrow({
230211
wallet: args.wallet as `0x${string}`,
@@ -238,7 +219,7 @@ export async function prepareAaveBorrow(args: PrepareAaveBorrowArgs): Promise<Un
238219
}
239220

240221
export async function prepareAaveRepay(args: PrepareAaveRepayArgs): Promise<UnsignedTx> {
241-
const meta = await resolveAssetMeta(args.chain as SupportedChain, args.asset as `0x${string}`);
222+
const meta = await resolveTokenMeta(args.chain as SupportedChain, args.asset as `0x${string}`);
242223
return enrichTx(
243224
await buildAaveRepay({
244225
wallet: args.wallet as `0x${string}`,
@@ -269,7 +250,7 @@ export async function prepareLidoUnstake(args: PrepareLidoUnstakeArgs): Promise<
269250
}
270251

271252
export async function prepareEigenLayerDeposit(args: PrepareEigenLayerDepositArgs): Promise<UnsignedTx> {
272-
const meta = await resolveAssetMeta("ethereum", args.token as `0x${string}`);
253+
const meta = await resolveTokenMeta("ethereum", args.token as `0x${string}`);
273254
return enrichTx(
274255
await buildEigenLayerDeposit({
275256
wallet: args.wallet as `0x${string}`,
@@ -306,7 +287,7 @@ export async function prepareTokenSend(args: PrepareTokenSendArgs): Promise<Unsi
306287
const chain = args.chain as SupportedChain;
307288
const token = args.token as `0x${string}`;
308289
const to = args.to as `0x${string}`;
309-
const meta = await resolveAssetMeta(chain, token);
290+
const meta = await resolveTokenMeta(chain, token);
310291

311292
let amountWei: bigint;
312293
let displayAmount = args.amount;

src/modules/morpho/actions.ts

Lines changed: 11 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { encodeFunctionData, parseUnits } from "viem";
22
import { morphoBlueAbi, type MorphoMarketParams } from "../../abis/morpho-blue.js";
3-
import { erc20Abi } from "../../abis/erc20.js";
43
import { getClient } from "../../data/rpc.js";
54
import { CONTRACTS } from "../../config/contracts.js";
6-
import { buildApprovalTx, resolveApprovalCap } from "../shared/approval.js";
5+
import { buildApprovalTx, chainApproval, resolveApprovalCap } from "../shared/approval.js";
6+
import { resolveTokenMeta } from "../shared/token-meta.js";
77
import type {
88
PrepareMorphoSupplyArgs,
99
PrepareMorphoWithdrawArgs,
@@ -47,21 +47,6 @@ async function resolveMarketParams(
4747
return { loanToken, collateralToken, oracle, irm, lltv };
4848
}
4949

50-
async function tokenMeta(
51-
chain: SupportedChain,
52-
asset: `0x${string}`
53-
): Promise<{ decimals: number; symbol: string }> {
54-
const client = getClient(chain);
55-
const [decimals, symbol] = await client.multicall({
56-
contracts: [
57-
{ address: asset, abi: erc20Abi, functionName: "decimals" },
58-
{ address: asset, abi: erc20Abi, functionName: "symbol" },
59-
],
60-
allowFailure: false,
61-
});
62-
return { decimals: Number(decimals), symbol: symbol as string };
63-
}
64-
6550
function paramsTuple(p: MorphoMarketParams) {
6651
return {
6752
loanToken: p.loanToken,
@@ -77,7 +62,7 @@ export async function buildMorphoSupply(p: PrepareMorphoSupplyArgs): Promise<Uns
7762
const wallet = p.wallet as `0x${string}`;
7863
const morpho = morphoAddress(chain);
7964
const params = await resolveMarketParams(chain, p.marketId as `0x${string}`);
80-
const meta = await tokenMeta(chain, params.loanToken);
65+
const meta = await resolveTokenMeta(chain, params.loanToken);
8166
const amountWei = parseUnits(p.amount, meta.decimals);
8267
const { approvalAmount, display } = resolveApprovalCap(
8368
p.approvalCap,
@@ -111,21 +96,15 @@ export async function buildMorphoSupply(p: PrepareMorphoSupplyArgs): Promise<Uns
11196
args: { marketId: p.marketId, amount: p.amount, onBehalf: wallet },
11297
},
11398
};
114-
if (approval) {
115-
let tail = approval;
116-
while (tail.next) tail = tail.next;
117-
tail.next = supplyTx;
118-
return approval;
119-
}
120-
return supplyTx;
99+
return chainApproval(approval, supplyTx);
121100
}
122101

123102
export async function buildMorphoWithdraw(p: PrepareMorphoWithdrawArgs): Promise<UnsignedTx> {
124103
const chain = p.chain as SupportedChain;
125104
const wallet = p.wallet as `0x${string}`;
126105
const morpho = morphoAddress(chain);
127106
const params = await resolveMarketParams(chain, p.marketId as `0x${string}`);
128-
const meta = await tokenMeta(chain, params.loanToken);
107+
const meta = await resolveTokenMeta(chain, params.loanToken);
129108
// "max" withdraw is encoded as shares=MaxUint256/2 would exceed position; safer to ask by assets with
130109
// a very large number. Morpho reverts on overdraw, so callers should read their position first.
131110
// Here we only support explicit amounts for withdraw.
@@ -158,7 +137,7 @@ export async function buildMorphoBorrow(p: PrepareMorphoBorrowArgs): Promise<Uns
158137
const wallet = p.wallet as `0x${string}`;
159138
const morpho = morphoAddress(chain);
160139
const params = await resolveMarketParams(chain, p.marketId as `0x${string}`);
161-
const meta = await tokenMeta(chain, params.loanToken);
140+
const meta = await resolveTokenMeta(chain, params.loanToken);
162141
const amountWei = parseUnits(p.amount, meta.decimals);
163142
return {
164143
chain,
@@ -183,7 +162,7 @@ export async function buildMorphoRepay(p: PrepareMorphoRepayArgs): Promise<Unsig
183162
const wallet = p.wallet as `0x${string}`;
184163
const morpho = morphoAddress(chain);
185164
const params = await resolveMarketParams(chain, p.marketId as `0x${string}`);
186-
const meta = await tokenMeta(chain, params.loanToken);
165+
const meta = await resolveTokenMeta(chain, params.loanToken);
187166
if (p.amount === "max") {
188167
throw new Error(
189168
`"max" is not supported for Morpho repay — read borrowShares and pass an explicit amount.`
@@ -222,13 +201,7 @@ export async function buildMorphoRepay(p: PrepareMorphoRepayArgs): Promise<Unsig
222201
args: { marketId: p.marketId, amount: p.amount, onBehalf: wallet },
223202
},
224203
};
225-
if (approval) {
226-
let tail = approval;
227-
while (tail.next) tail = tail.next;
228-
tail.next = repayTx;
229-
return approval;
230-
}
231-
return repayTx;
204+
return chainApproval(approval, repayTx);
232205
}
233206

234207
export async function buildMorphoSupplyCollateral(
@@ -238,7 +211,7 @@ export async function buildMorphoSupplyCollateral(
238211
const wallet = p.wallet as `0x${string}`;
239212
const morpho = morphoAddress(chain);
240213
const params = await resolveMarketParams(chain, p.marketId as `0x${string}`);
241-
const meta = await tokenMeta(chain, params.collateralToken);
214+
const meta = await resolveTokenMeta(chain, params.collateralToken);
242215
const amountWei = parseUnits(p.amount, meta.decimals);
243216
const { approvalAmount, display } = resolveApprovalCap(
244217
p.approvalCap,
@@ -272,13 +245,7 @@ export async function buildMorphoSupplyCollateral(
272245
args: { marketId: p.marketId, amount: p.amount, onBehalf: wallet },
273246
},
274247
};
275-
if (approval) {
276-
let tail = approval;
277-
while (tail.next) tail = tail.next;
278-
tail.next = tx;
279-
return approval;
280-
}
281-
return tx;
248+
return chainApproval(approval, tx);
282249
}
283250

284251
export async function buildMorphoWithdrawCollateral(
@@ -288,7 +255,7 @@ export async function buildMorphoWithdrawCollateral(
288255
const wallet = p.wallet as `0x${string}`;
289256
const morpho = morphoAddress(chain);
290257
const params = await resolveMarketParams(chain, p.marketId as `0x${string}`);
291-
const meta = await tokenMeta(chain, params.collateralToken);
258+
const meta = await resolveTokenMeta(chain, params.collateralToken);
292259
if (p.amount === "max") {
293260
throw new Error(
294261
`"max" is not supported for Morpho withdrawCollateral — read position.collateral and pass an explicit amount.`

0 commit comments

Comments
 (0)