Skip to content

Commit 3c97133

Browse files
committed
feat(vv2mmv1AdapterV2): add fetcher
1 parent 920a7a0 commit 3c97133

File tree

9 files changed

+369
-30
lines changed

9 files changed

+369
-30
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity ^0.8.0;
3+
4+
import {IMorphoMarketV1AdapterV2} from "./interfaces/IMorphoMarketV1AdapterV2.sol";
5+
import {MarketParams} from "../interfaces/IMorpho.sol";
6+
7+
struct VaultV2MorphoMarketV1AdapterV2Response {
8+
address parentVault;
9+
address skimRecipient;
10+
address adaptiveCurveIrm;
11+
bytes32[] marketIds;
12+
uint256[] supplyShares;
13+
}
14+
15+
contract GetVaultV2MorphoMarketV1AdapterV2 {
16+
function query(IMorphoMarketV1AdapterV2 adapter)
17+
external
18+
view
19+
returns (VaultV2MorphoMarketV1AdapterV2Response memory res)
20+
{
21+
res.parentVault = adapter.parentVault();
22+
res.skimRecipient = adapter.skimRecipient();
23+
res.adaptiveCurveIrm = adapter.adaptiveCurveIrm();
24+
25+
uint256 length = adapter.marketIdsLength();
26+
res.marketIds = new bytes32[](length);
27+
res.supplyShares = new uint256[](length);
28+
for (uint256 i = 0; i < length; i++) {
29+
bytes32 marketId = adapter.marketIds(i);
30+
res.marketIds[i] = marketId;
31+
res.supplyShares[i] = adapter.supplyShares(marketId);
32+
}
33+
}
34+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
// Copyright (c) 2025 Morpho Association
3+
pragma solidity >=0.5.0;
4+
5+
import {IAdapter} from "./IAdapter.sol";
6+
import {MarketParams} from "../../interfaces/IMorpho.sol";
7+
8+
interface IMorphoMarketV1AdapterV2 is IAdapter {
9+
/* EVENTS */
10+
11+
event Submit(bytes4 indexed selector, bytes data, uint256 executableAt);
12+
event Revoke(address indexed sender, bytes4 indexed selector, bytes data);
13+
event Accept(bytes4 indexed selector, bytes data);
14+
event Abdicate(bytes4 indexed selector);
15+
event IncreaseTimelock(bytes4 indexed selector, uint256 newDuration);
16+
event DecreaseTimelock(bytes4 indexed selector, uint256 newDuration);
17+
event SetSkimRecipient(address indexed newSkimRecipient);
18+
event Skim(address indexed token, uint256 assets);
19+
event BurnShares(bytes32 indexed marketId, uint256 supplyShares);
20+
event Allocate(bytes32 indexed marketId, uint256 newAllocation, uint256 mintedShares);
21+
event Deallocate(bytes32 indexed marketId, uint256 newAllocation, uint256 burnedShares);
22+
23+
/* ERRORS */
24+
25+
error Abdicated();
26+
error AutomaticallyTimelocked();
27+
error DataAlreadyPending();
28+
error DataNotTimelocked();
29+
error IrmMismatch();
30+
error LoanAssetMismatch();
31+
error SharePriceAboveOne();
32+
error TimelockNotDecreasing();
33+
error TimelockNotExpired();
34+
error TimelockNotIncreasing();
35+
error Unauthorized();
36+
37+
/* VIEW FUNCTIONS */
38+
39+
function factory() external view returns (address);
40+
function parentVault() external view returns (address);
41+
function asset() external view returns (address);
42+
function morpho() external view returns (address);
43+
function marketIds(uint256 index) external view returns (bytes32);
44+
function supplyShares(bytes32 marketId) external view returns (uint256);
45+
function adapterId() external view returns (bytes32);
46+
function skimRecipient() external view returns (address);
47+
function marketIdsLength() external view returns (uint256);
48+
function adaptiveCurveIrm() external view returns (address);
49+
function allocation(MarketParams memory marketParams) external view returns (uint256);
50+
function expectedSupplyAssets(bytes32 marketId) external view returns (uint256);
51+
function ids(MarketParams memory marketParams) external view returns (bytes32[] memory);
52+
function timelock(bytes4 selector) external view returns (uint256);
53+
function abdicated(bytes4 selector) external view returns (bool);
54+
function executableAt(bytes memory data) external view returns (uint256);
55+
56+
/* NON-VIEW FUNCTIONS */
57+
58+
function submit(bytes memory data) external;
59+
function revoke(bytes memory data) external;
60+
function increaseTimelock(bytes4 selector, uint256 newDuration) external;
61+
function decreaseTimelock(bytes4 selector, uint256 newDuration) external;
62+
function abdicate(bytes4 selector) external;
63+
function setSkimRecipient(address newSkimRecipient) external;
64+
function burnShares(bytes32 marketId) external;
65+
function skim(address token) external;
66+
}

packages/blue-sdk-viem/src/abis.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11994,7 +11994,7 @@ export const vaultV1AdapterFactoryAbi = morphoVaultV1AdapterFactoryAbi;
1199411994
*/
1199511995
export const vaultV1AdapterAbi = morphoVaultV1AdapterAbi;
1199611996

11997-
export const morphoMarketV1AdapterAbiV2 = [
11997+
export const morphoMarketV1AdapterV2Abi = [
1199811998
{
1199911999
inputs: [
1200012000
{ internalType: "address", name: "_parentVault", type: "address" },
@@ -12467,7 +12467,7 @@ export const morphoMarketV1AdapterAbiV2 = [
1246712467
},
1246812468
] as const;
1246912469

12470-
export const morphoMarketV1AdapterFactoryAbiV2 = [
12470+
export const morphoMarketV1AdapterV2FactoryAbi = [
1247112471
{
1247212472
inputs: [
1247312473
{ internalType: "address", name: "_morpho", type: "address" },

packages/blue-sdk-viem/src/fetch/vault-v2/VaultV2Adapter.ts

Lines changed: 56 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,18 @@ import {
44
} from "@morpho-org/blue-sdk";
55
import type { Address, Client } from "viem";
66
import { getChainId, readContract } from "viem/actions";
7-
import { morphoVaultV1AdapterFactoryAbi } from "../../abis";
7+
import {
8+
morphoMarketV1AdapterV2FactoryAbi,
9+
morphoVaultV1AdapterFactoryAbi,
10+
} from "../../abis";
811
import { morphoMarketV1AdapterFactoryAbi } from "../../abis";
912
import type { DeploylessFetchParameters } from "../../types";
1013
import { fetchVaultV2MorphoMarketV1Adapter } from "./VaultV2MorphoMarketV1Adapter";
1114
import { fetchAccrualVaultV2MorphoMarketV1Adapter } from "./VaultV2MorphoMarketV1Adapter";
15+
import {
16+
fetchAccrualVaultV2MorphoMarketV1AdapterV2,
17+
fetchVaultV2MorphoMarketV1AdapterV2,
18+
} from "./VaultV2MorphoMarketV1AdapterV2";
1219
import {
1320
fetchAccrualVaultV2MorphoVaultV1Adapter,
1421
fetchVaultV2MorphoVaultV1Adapter,
@@ -22,10 +29,17 @@ export async function fetchVaultV2Adapter(
2229
parameters.chainId ??= await getChainId(client);
2330
parameters.deployless ??= true;
2431

25-
const { morphoVaultV1AdapterFactory, morphoMarketV1AdapterFactory } =
26-
getChainAddresses(parameters.chainId);
32+
const {
33+
morphoVaultV1AdapterFactory,
34+
morphoMarketV1AdapterFactory,
35+
morphoMarketV1AdapterV2Factory,
36+
} = getChainAddresses(parameters.chainId);
2737

28-
const [isMorphoVaultV1Adapter, isMorphoMarketV1Adapter] = await Promise.all([
38+
const [
39+
isMorphoVaultV1Adapter,
40+
isMorphoMarketV1Adapter,
41+
isMorphoMarketV1AdapterV2,
42+
] = await Promise.all([
2943
morphoVaultV1AdapterFactory
3044
? readContract(client, {
3145
...parameters,
@@ -44,6 +58,15 @@ export async function fetchVaultV2Adapter(
4458
args: [address],
4559
})
4660
: false,
61+
morphoMarketV1AdapterV2Factory
62+
? readContract(client, {
63+
...parameters,
64+
address: morphoMarketV1AdapterV2Factory,
65+
abi: morphoMarketV1AdapterV2FactoryAbi,
66+
functionName: "isMorphoMarketV1AdapterV2",
67+
args: [address],
68+
})
69+
: false,
4770
]);
4871

4972
if (isMorphoVaultV1Adapter)
@@ -52,6 +75,9 @@ export async function fetchVaultV2Adapter(
5275
if (isMorphoMarketV1Adapter)
5376
return fetchVaultV2MorphoMarketV1Adapter(address, client, parameters);
5477

78+
if (isMorphoMarketV1AdapterV2)
79+
return fetchVaultV2MorphoMarketV1AdapterV2(address, client, parameters);
80+
5581
throw new UnsupportedVaultV2AdapterError(address);
5682
}
5783

@@ -63,10 +89,17 @@ export async function fetchAccrualVaultV2Adapter(
6389
parameters.chainId ??= await getChainId(client);
6490
parameters.deployless ??= true;
6591

66-
const { morphoVaultV1AdapterFactory, morphoMarketV1AdapterFactory } =
67-
getChainAddresses(parameters.chainId);
92+
const {
93+
morphoVaultV1AdapterFactory,
94+
morphoMarketV1AdapterFactory,
95+
morphoMarketV1AdapterV2Factory,
96+
} = getChainAddresses(parameters.chainId);
6897

69-
const [isMorphoVaultV1Adapter, isMorphoMarketV1Adapter] = await Promise.all([
98+
const [
99+
isMorphoVaultV1Adapter,
100+
isMorphoMarketV1Adapter,
101+
isMorphoMarketV1AdapterV2,
102+
] = await Promise.all([
70103
morphoVaultV1AdapterFactory
71104
? readContract(client, {
72105
...parameters,
@@ -85,6 +118,15 @@ export async function fetchAccrualVaultV2Adapter(
85118
args: [address],
86119
})
87120
: false,
121+
morphoMarketV1AdapterV2Factory
122+
? readContract(client, {
123+
...parameters,
124+
address: morphoMarketV1AdapterV2Factory,
125+
abi: morphoMarketV1AdapterV2FactoryAbi,
126+
functionName: "isMorphoMarketV1AdapterV2",
127+
args: [address],
128+
})
129+
: false,
88130
]);
89131

90132
if (isMorphoVaultV1Adapter)
@@ -97,5 +139,12 @@ export async function fetchAccrualVaultV2Adapter(
97139
parameters,
98140
);
99141

142+
if (isMorphoMarketV1AdapterV2)
143+
return fetchAccrualVaultV2MorphoMarketV1AdapterV2(
144+
address,
145+
client,
146+
parameters,
147+
);
148+
100149
throw new UnsupportedVaultV2AdapterError(address);
101150
}
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
import {
2+
AccrualVaultV2MorphoMarketV1AdapterV2,
3+
type MarketId,
4+
VaultV2MorphoMarketV1AdapterV2,
5+
} from "@morpho-org/blue-sdk";
6+
import { fromEntries } from "@morpho-org/morpho-ts";
7+
import type { Address, Client } from "viem";
8+
import { getChainId, readContract } from "viem/actions";
9+
import { morphoMarketV1AdapterV2Abi } from "../../abis";
10+
import {
11+
abi,
12+
code,
13+
} from "../../queries/vault-v2/GetVaultV2MorphoMarketV1AdapterV2";
14+
import type { DeploylessFetchParameters } from "../../types";
15+
import { fetchMarket } from "../Market";
16+
17+
export async function fetchVaultV2MorphoMarketV1AdapterV2(
18+
address: Address,
19+
client: Client,
20+
{ deployless = true, ...parameters }: DeploylessFetchParameters = {},
21+
) {
22+
parameters.chainId ??= await getChainId(client);
23+
24+
if (deployless) {
25+
try {
26+
const adapter = await readContract(client, {
27+
...parameters,
28+
abi,
29+
code,
30+
functionName: "query",
31+
args: [address],
32+
});
33+
34+
return new VaultV2MorphoMarketV1AdapterV2({
35+
...adapter,
36+
marketIds: [...adapter.marketIds] as MarketId[],
37+
supplyShares: fromEntries(
38+
(adapter.marketIds as MarketId[]).map((marketId, i) => [
39+
marketId,
40+
adapter.supplyShares[i]!,
41+
]),
42+
),
43+
address,
44+
});
45+
} catch {
46+
// Fallback to multicall if deployless call fails.
47+
}
48+
}
49+
50+
const [parentVault, skimRecipient, marketIdsLength, adaptiveCurveIrm] =
51+
await Promise.all([
52+
readContract(client, {
53+
...parameters,
54+
address,
55+
abi: morphoMarketV1AdapterV2Abi,
56+
functionName: "parentVault",
57+
}),
58+
readContract(client, {
59+
...parameters,
60+
address,
61+
abi: morphoMarketV1AdapterV2Abi,
62+
functionName: "skimRecipient",
63+
}),
64+
readContract(client, {
65+
...parameters,
66+
address,
67+
abi: morphoMarketV1AdapterV2Abi,
68+
functionName: "marketIdsLength",
69+
}),
70+
readContract(client, {
71+
...parameters,
72+
address,
73+
abi: morphoMarketV1AdapterV2Abi,
74+
functionName: "adaptiveCurveIrm",
75+
}),
76+
]);
77+
78+
const marketIds = await Promise.all(
79+
Array.from(
80+
{ length: Number(marketIdsLength) },
81+
(_, i) =>
82+
readContract(client, {
83+
...parameters,
84+
address,
85+
abi: morphoMarketV1AdapterV2Abi,
86+
functionName: "marketIds",
87+
args: [BigInt(i)],
88+
}) as Promise<MarketId>,
89+
),
90+
);
91+
92+
const supplyShares = await Promise.all(
93+
marketIds.map(
94+
async (marketId) =>
95+
[
96+
marketId,
97+
await readContract(client, {
98+
...parameters,
99+
address,
100+
abi: morphoMarketV1AdapterV2Abi,
101+
functionName: "supplyShares",
102+
args: [marketId],
103+
}),
104+
] as const,
105+
),
106+
).then(fromEntries);
107+
108+
return new VaultV2MorphoMarketV1AdapterV2({
109+
parentVault,
110+
skimRecipient,
111+
address,
112+
marketIds,
113+
adaptiveCurveIrm,
114+
supplyShares,
115+
});
116+
}
117+
118+
export async function fetchAccrualVaultV2MorphoMarketV1AdapterV2(
119+
address: Address,
120+
client: Client,
121+
parameters: DeploylessFetchParameters = {},
122+
) {
123+
const adapter = await fetchVaultV2MorphoMarketV1AdapterV2(
124+
address,
125+
client,
126+
parameters,
127+
);
128+
const markets = await Promise.all(
129+
adapter.marketIds.map((marketId) =>
130+
fetchMarket(marketId, client, parameters),
131+
),
132+
);
133+
134+
return new AccrualVaultV2MorphoMarketV1AdapterV2(adapter, markets);
135+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
export * from "./VaultV2";
22
export * from "./VaultV2MorphoVaultV1Adapter";
33
export * from "./VaultV2Adapter";
4+
export * from "./VaultV2MorphoMarketV1AdapterV2";
5+
export * from "./VaultV2MorphoMarketV1Adapter";

0 commit comments

Comments
 (0)