@morpho-org/blue-sdk 1.0.1 → 1.0.3

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.
Files changed (150) hide show
  1. package/package.json +10 -7
  2. package/src/addresses.ts +247 -0
  3. package/src/chain/chain.constants.ts +235 -0
  4. package/src/chain/chain.test.ts +51 -0
  5. package/src/chain/chain.types.ts +42 -0
  6. package/src/chain/chain.utils.ts +44 -0
  7. package/src/constants.ts +18 -0
  8. package/src/errors.ts +75 -0
  9. package/src/ethers/ethers.test.ts +17 -0
  10. package/src/ethers/safeGetAddress.ts +4 -0
  11. package/src/ethers/safeParseUnits.ts +29 -0
  12. package/src/evm.ts +172 -0
  13. package/src/helpers/format/format.test.ts +340 -0
  14. package/src/helpers/format/format.ts +416 -0
  15. package/src/helpers/getChecksumedAddress.ts +15 -0
  16. package/{lib/helpers/isZeroAddressOrUnset.d.ts → src/helpers/isZeroAddressOrUnset.ts} +7 -1
  17. package/src/helpers/locale.ts +108 -0
  18. package/src/holding/Holding.ts +109 -0
  19. package/src/market/Market.ts +479 -0
  20. package/src/market/MarketConfig.ts +108 -0
  21. package/src/market/MarketUtils.test.ts +25 -0
  22. package/src/market/MarketUtils.ts +467 -0
  23. package/src/maths/AdaptiveCurveIrmLib.ts +143 -0
  24. package/src/maths/MathLib.ts +208 -0
  25. package/src/maths/MathUtils.ts +31 -0
  26. package/src/maths/SharesMath.ts +40 -0
  27. package/src/notifications.ts +167 -0
  28. package/src/position/Position.ts +251 -0
  29. package/src/signatures/index.ts +18 -0
  30. package/src/signatures/manager.ts +50 -0
  31. package/src/signatures/permit.ts +126 -0
  32. package/src/signatures/permit2.ts +120 -0
  33. package/src/signatures/types.ts +18 -0
  34. package/src/signatures/utils.ts +83 -0
  35. package/src/tests/mocks/markets.ts +110 -0
  36. package/src/token/ERC20Metadata.ts +124 -0
  37. package/src/token/Token.ts +83 -0
  38. package/src/token/TokenNamespace.ts +76 -0
  39. package/src/token/WrappedToken.ts +142 -0
  40. package/src/types.ts +37 -0
  41. package/src/user/User.ts +32 -0
  42. package/src/user/user.types.ts +25 -0
  43. package/src/vault/Vault.ts +370 -0
  44. package/src/vault/VaultAllocation.ts +58 -0
  45. package/src/vault/VaultConfig.ts +55 -0
  46. package/src/vault/VaultUtils.ts +47 -0
  47. package/lib/addresses.d.ts +0 -168
  48. package/lib/addresses.js +0 -169
  49. package/lib/chain/chain.constants.d.ts +0 -3
  50. package/lib/chain/chain.constants.js +0 -232
  51. package/lib/chain/chain.types.d.ts +0 -20
  52. package/lib/chain/chain.types.js +0 -30
  53. package/lib/chain/chain.utils.d.ts +0 -14
  54. package/lib/chain/chain.utils.js +0 -30
  55. package/lib/chain/index.js +0 -18
  56. package/lib/constants.d.ts +0 -8
  57. package/lib/constants.js +0 -13
  58. package/lib/errors.d.ts +0 -37
  59. package/lib/errors.js +0 -71
  60. package/lib/ethers/index.js +0 -18
  61. package/lib/ethers/safeGetAddress.d.ts +0 -1
  62. package/lib/ethers/safeGetAddress.js +0 -6
  63. package/lib/ethers/safeParseUnits.d.ts +0 -2
  64. package/lib/ethers/safeParseUnits.js +0 -25
  65. package/lib/evm.d.ts +0 -36
  66. package/lib/evm.js +0 -113
  67. package/lib/helpers/format/format.d.ts +0 -98
  68. package/lib/helpers/format/format.js +0 -301
  69. package/lib/helpers/format/index.js +0 -17
  70. package/lib/helpers/getChecksumedAddress.d.ts +0 -7
  71. package/lib/helpers/getChecksumedAddress.js +0 -17
  72. package/lib/helpers/index.js +0 -20
  73. package/lib/helpers/isZeroAddressOrUnset.js +0 -14
  74. package/lib/helpers/locale.d.ts +0 -36
  75. package/lib/helpers/locale.js +0 -86
  76. package/lib/holding/Holding.d.ts +0 -60
  77. package/lib/holding/Holding.js +0 -31
  78. package/lib/holding/index.js +0 -17
  79. package/lib/index.d.ts +0 -33
  80. package/lib/market/Market.d.ts +0 -159
  81. package/lib/market/Market.js +0 -240
  82. package/lib/market/MarketConfig.d.ts +0 -44
  83. package/lib/market/MarketConfig.js +0 -56
  84. package/lib/market/MarketUtils.d.ts +0 -165
  85. package/lib/market/MarketUtils.js +0 -182
  86. package/lib/market/index.js +0 -19
  87. package/lib/maths/AdaptiveCurveIrmLib.d.ts +0 -37
  88. package/lib/maths/AdaptiveCurveIrmLib.js +0 -116
  89. package/lib/maths/MathLib.d.ts +0 -94
  90. package/lib/maths/MathLib.js +0 -153
  91. package/lib/maths/MathUtils.d.ts +0 -15
  92. package/lib/maths/MathUtils.js +0 -33
  93. package/lib/maths/SharesMath.d.ts +0 -12
  94. package/lib/maths/SharesMath.js +0 -22
  95. package/lib/maths/index.js +0 -20
  96. package/lib/notifications.d.ts +0 -98
  97. package/lib/notifications.js +0 -52
  98. package/lib/position/Position.d.ts +0 -118
  99. package/lib/position/Position.js +0 -145
  100. package/lib/position/index.js +0 -17
  101. package/lib/signatures/index.d.ts +0 -12
  102. package/lib/signatures/index.js +0 -39
  103. package/lib/signatures/manager.d.ts +0 -10
  104. package/lib/signatures/manager.js +0 -37
  105. package/lib/signatures/permit.d.ts +0 -21
  106. package/lib/signatures/permit.js +0 -101
  107. package/lib/signatures/permit2.d.ts +0 -20
  108. package/lib/signatures/permit2.js +0 -91
  109. package/lib/signatures/types.d.ts +0 -13
  110. package/lib/signatures/types.js +0 -2
  111. package/lib/signatures/utils.d.ts +0 -6
  112. package/lib/signatures/utils.js +0 -44
  113. package/lib/tests/mocks/markets.d.ts +0 -17
  114. package/lib/tests/mocks/markets.js +0 -108
  115. package/lib/token/ERC20Metadata.d.ts +0 -249
  116. package/lib/token/ERC20Metadata.js +0 -81
  117. package/lib/token/Token.d.ts +0 -45
  118. package/lib/token/Token.js +0 -39
  119. package/lib/token/TokenNamespace.d.ts +0 -18
  120. package/lib/token/TokenNamespace.js +0 -55
  121. package/lib/token/WrappedToken.d.ts +0 -42
  122. package/lib/token/WrappedToken.js +0 -87
  123. package/lib/token/index.js +0 -18
  124. package/lib/types.d.ts +0 -29
  125. package/lib/types.js +0 -23
  126. package/lib/user/User.d.ts +0 -20
  127. package/lib/user/User.js +0 -11
  128. package/lib/user/index.js +0 -18
  129. package/lib/user/user.types.d.ts +0 -18
  130. package/lib/user/user.types.js +0 -2
  131. package/lib/vault/Vault.d.ts +0 -167
  132. package/lib/vault/Vault.js +0 -156
  133. package/lib/vault/VaultAllocation.d.ts +0 -38
  134. package/lib/vault/VaultAllocation.js +0 -18
  135. package/lib/vault/VaultConfig.d.ts +0 -23
  136. package/lib/vault/VaultConfig.js +0 -26
  137. package/lib/vault/VaultUtils.d.ts +0 -17
  138. package/lib/vault/VaultUtils.js +0 -17
  139. package/lib/vault/index.js +0 -20
  140. /package/{lib/chain/index.d.ts → src/chain/index.ts} +0 -0
  141. /package/{lib/ethers/index.d.ts → src/ethers/index.ts} +0 -0
  142. /package/{lib/helpers/format/index.d.ts → src/helpers/format/index.ts} +0 -0
  143. /package/{lib/helpers/index.d.ts → src/helpers/index.ts} +0 -0
  144. /package/{lib/holding/index.d.ts → src/holding/index.ts} +0 -0
  145. /package/{lib/market/index.d.ts → src/market/index.ts} +0 -0
  146. /package/{lib/maths/index.d.ts → src/maths/index.ts} +0 -0
  147. /package/{lib/position/index.d.ts → src/position/index.ts} +0 -0
  148. /package/{lib/token/index.d.ts → src/token/index.ts} +0 -0
  149. /package/{lib/user/index.d.ts → src/user/index.ts} +0 -0
  150. /package/{lib/vault/index.d.ts → src/vault/index.ts} +0 -0
@@ -0,0 +1,50 @@
1
+ import { getChainAddresses } from "../addresses";
2
+ import { ChainId } from "../chain";
3
+
4
+ import { SignatureMessage } from "./types";
5
+ import { getMessage } from "./utils";
6
+
7
+ export interface ManagerApprovalSignatureArgs {
8
+ authorizer: string;
9
+ authorized: string;
10
+ isAuthorized: boolean;
11
+ nonce: bigint;
12
+ deadline: bigint;
13
+ }
14
+
15
+ export const getManagerApprovalMessage = (
16
+ args: ManagerApprovalSignatureArgs,
17
+ chainId: ChainId
18
+ ): SignatureMessage => {
19
+ const domain = {
20
+ chainId: chainId.toString(),
21
+ verifyingContract: getChainAddresses(chainId).morpho,
22
+ };
23
+
24
+ const types = {
25
+ Authorization: [
26
+ {
27
+ name: "authorizer",
28
+ type: "address",
29
+ },
30
+ {
31
+ name: "authorized",
32
+ type: "address",
33
+ },
34
+ {
35
+ name: "isAuthorized",
36
+ type: "bool",
37
+ },
38
+ {
39
+ name: "nonce",
40
+ type: "uint256",
41
+ },
42
+ {
43
+ name: "deadline",
44
+ type: "uint256",
45
+ },
46
+ ],
47
+ };
48
+
49
+ return getMessage(domain, types, args);
50
+ };
@@ -0,0 +1,126 @@
1
+ import { addresses, getChainAddresses } from "../addresses";
2
+ import { ChainId } from "../chain";
3
+ import { Token } from "../token";
4
+ import { Address } from "../types";
5
+
6
+ import { SignatureMessage } from "./types";
7
+ import { getMessage } from "./utils";
8
+
9
+ export interface PermitArgs {
10
+ erc20: Token;
11
+ owner: Address;
12
+ spender: Address;
13
+ allowance: bigint;
14
+ nonce: bigint;
15
+ deadline: bigint;
16
+ }
17
+
18
+ /**
19
+ * Permit signature for ERC20 tokens, following EIP-2612.
20
+ * Docs: https://eips.ethereum.org/EIPS/eip-2612
21
+ */
22
+ export const getPermitMessage = (
23
+ { deadline, owner, nonce, spender, erc20, allowance }: PermitArgs,
24
+ chainId: ChainId
25
+ ): SignatureMessage => {
26
+ const { usdc, dai } = getChainAddresses(chainId);
27
+
28
+ const domain = {
29
+ name: erc20.name,
30
+ version: erc20.address === usdc ? "2" : "1",
31
+ chainId: chainId.toString(),
32
+ verifyingContract: erc20.address,
33
+ };
34
+
35
+ if (erc20.address === dai)
36
+ return getMessage(
37
+ domain,
38
+ {
39
+ Permit: [
40
+ {
41
+ name: "holder",
42
+ type: "address",
43
+ },
44
+ {
45
+ name: "spender",
46
+ type: "address",
47
+ },
48
+ {
49
+ name: "nonce",
50
+ type: "uint256",
51
+ },
52
+ {
53
+ name: "expiry",
54
+ type: "uint256",
55
+ },
56
+ {
57
+ name: "allowed",
58
+ type: "bool",
59
+ },
60
+ ],
61
+ },
62
+ {
63
+ holder: owner,
64
+ spender,
65
+ allowed: allowance > 0n,
66
+ nonce,
67
+ expiry: deadline,
68
+ }
69
+ );
70
+
71
+ const types = {
72
+ Permit: [
73
+ {
74
+ name: "owner",
75
+ type: "address",
76
+ },
77
+ {
78
+ name: "spender",
79
+ type: "address",
80
+ },
81
+ {
82
+ name: "value",
83
+ type: "uint256",
84
+ },
85
+ {
86
+ name: "nonce",
87
+ type: "uint256",
88
+ },
89
+ {
90
+ name: "deadline",
91
+ type: "uint256",
92
+ },
93
+ ],
94
+ };
95
+ const value = {
96
+ owner,
97
+ spender,
98
+ value: allowance,
99
+ nonce,
100
+ deadline,
101
+ };
102
+
103
+ return getMessage(domain, types, value);
104
+ };
105
+
106
+ export const WITH_SIMPLE_PERMIT: {
107
+ [id in ChainId]: (Address | undefined)[];
108
+ } = {
109
+ [ChainId.EthMainnet]: [
110
+ addresses[ChainId.EthMainnet].wbIB01,
111
+ addresses[ChainId.EthMainnet].wbC3M,
112
+ addresses[ChainId.EthMainnet].wstEth,
113
+ addresses[ChainId.EthMainnet].sDai,
114
+ addresses[ChainId.EthMainnet].osEth,
115
+ addresses[ChainId.EthMainnet].usdc,
116
+ addresses[ChainId.EthMainnet].dai,
117
+ ],
118
+ [ChainId.EthGoerliTestnet]: [
119
+ "0x0aCd15Fb54034492c392596B56ED415bD07e70d7", // Fake DAI
120
+ "0xD8134205b0328F5676aaeFb3B2a0DC15f4029d8C", // Real sDAI
121
+ ],
122
+ [ChainId.BaseMainnet]: [addresses[ChainId.BaseMainnet].usdc],
123
+ };
124
+
125
+ export const hasSimplePermit = (chainId: ChainId, address: Address) =>
126
+ WITH_SIMPLE_PERMIT[chainId]?.includes(address);
@@ -0,0 +1,120 @@
1
+ import { getChainAddresses } from "../addresses";
2
+ import { ChainId } from "../chain";
3
+ import { MathLib } from "../maths";
4
+ import { Address } from "../types";
5
+
6
+ import { SignatureMessage } from "./types";
7
+ import { getMessage } from "./utils";
8
+
9
+ export interface Permit2Args {
10
+ erc20: Address;
11
+ allowance: bigint;
12
+ nonce: bigint;
13
+ deadline: bigint;
14
+ spender: Address;
15
+ expiration?: bigint;
16
+ }
17
+
18
+ export interface Permit2TransferFromArgs {
19
+ erc20: Address;
20
+ allowance: bigint;
21
+ spender: Address;
22
+ nonce: bigint;
23
+ deadline: bigint;
24
+ }
25
+
26
+ export const getPermit2TransferFromMessage = (
27
+ args: Permit2TransferFromArgs,
28
+ chainId: ChainId
29
+ ) => {
30
+ const domain = {
31
+ name: "Permit2",
32
+ chainId: chainId.toString(),
33
+ verifyingContract: getChainAddresses(chainId).permit2,
34
+ };
35
+ const types = {
36
+ PermitTransferFrom: [
37
+ { name: "permitted", type: "TokenPermissions" },
38
+ { name: "spender", type: "address" },
39
+ { name: "nonce", type: "uint256" },
40
+ { name: "deadline", type: "uint256" },
41
+ ],
42
+ TokenPermissions: [
43
+ { name: "token", type: "address" },
44
+ { name: "amount", type: "uint256" },
45
+ ],
46
+ };
47
+ const value = {
48
+ permitted: {
49
+ token: args.erc20,
50
+ amount: MathLib.min(args.allowance, MathLib.MAX_UINT_160),
51
+ },
52
+ spender: args.spender,
53
+ nonce: args.nonce,
54
+ deadline: args.deadline,
55
+ };
56
+
57
+ return getMessage(domain, types, value);
58
+ };
59
+
60
+ export const getPermit2Message = (
61
+ args: Permit2Args,
62
+ chainId: ChainId
63
+ ): SignatureMessage => {
64
+ const domain = {
65
+ name: "Permit2",
66
+ chainId: chainId.toString(),
67
+ verifyingContract: getChainAddresses(chainId).permit2,
68
+ };
69
+ const types = {
70
+ PermitSingle: [
71
+ {
72
+ name: "details",
73
+ type: "PermitDetails",
74
+ },
75
+ {
76
+ name: "spender",
77
+ type: "address",
78
+ },
79
+ {
80
+ name: "sigDeadline",
81
+ type: "uint256",
82
+ },
83
+ ],
84
+ PermitDetails: [
85
+ {
86
+ name: "token",
87
+ type: "address",
88
+ },
89
+ {
90
+ name: "amount",
91
+ type: "uint160",
92
+ },
93
+ {
94
+ name: "expiration",
95
+ type: "uint48",
96
+ },
97
+ {
98
+ name: "nonce",
99
+ type: "uint48",
100
+ },
101
+ ],
102
+ };
103
+ const value = {
104
+ details: {
105
+ token: args.erc20,
106
+ amount: MathLib.min(args.allowance, MathLib.MAX_UINT_160),
107
+ // Use an unlimited expiration because it most
108
+ // closely mimics how a standard approval works.
109
+ expiration: MathLib.min(
110
+ args.expiration ?? MathLib.MAX_UINT_48,
111
+ MathLib.MAX_UINT_48
112
+ ),
113
+ nonce: args.nonce,
114
+ },
115
+ spender: args.spender,
116
+ sigDeadline: args.deadline,
117
+ };
118
+
119
+ return getMessage(domain, types, value);
120
+ };
@@ -0,0 +1,18 @@
1
+ import { TypedDataDomain } from "ethers";
2
+
3
+ export interface SignatureData {
4
+ domain: TypedDataDomain;
5
+ types: Record<
6
+ string,
7
+ {
8
+ name: string;
9
+ type: string;
10
+ }[]
11
+ >;
12
+ value: object;
13
+ }
14
+
15
+ export interface SignatureMessage {
16
+ hash: string;
17
+ data: SignatureData;
18
+ }
@@ -0,0 +1,83 @@
1
+ import {
2
+ Signature,
3
+ Signer,
4
+ TypedDataDomain,
5
+ TypedDataEncoder,
6
+ TypedDataField,
7
+ ZeroAddress,
8
+ recoverAddress,
9
+ } from "ethers";
10
+
11
+ import { InvalidSignatureError } from "../errors";
12
+ import { Address } from "../types";
13
+
14
+ import { SignatureMessage } from "./types";
15
+
16
+ export async function safeSignTypedData(
17
+ signer: Signer,
18
+ domain: TypedDataDomain,
19
+ types: Record<string, TypedDataField[]>,
20
+ value: Record<string, any>
21
+ ) {
22
+ const populated = await TypedDataEncoder.resolveNames(
23
+ domain,
24
+ types,
25
+ value,
26
+ (name: string) => {
27
+ return signer.resolveName(name) as Promise<string>;
28
+ }
29
+ );
30
+
31
+ // Fix the chainId parsing issue
32
+ // Tracking of https://github.com/ethers-io/ethers.js/issues/4649
33
+ const initialPayload = TypedDataEncoder.getPayload(
34
+ populated.domain,
35
+ types,
36
+ populated.value
37
+ );
38
+ const provider = signer.provider;
39
+ const unsafeChainId = Number(initialPayload.domain.chainId);
40
+
41
+ if (provider && "send" in provider && Number.isSafeInteger(unsafeChainId)) {
42
+ const correctedPayload = {
43
+ ...initialPayload,
44
+ domain: {
45
+ ...initialPayload.domain,
46
+ chainId: unsafeChainId, // that is safe now
47
+ },
48
+ };
49
+ return Signature.from(
50
+ // @ts-ignore if send is defined in the provider, it accepts raw RPC call args
51
+ await signer.provider!.send("eth_signTypedData_v4", [
52
+ // Doing the same thing that inside of the signTypedData function.
53
+ await signer.getAddress().then((r) => r.toLowerCase()),
54
+ JSON.stringify(correctedPayload),
55
+ ])
56
+ );
57
+ }
58
+
59
+ return Signature.from(
60
+ await signer.signTypedData(populated.domain, types, populated.value)
61
+ );
62
+ }
63
+
64
+ export function verifySignature(
65
+ signature: Signature,
66
+ hash: string,
67
+ signerAddress: Address
68
+ ) {
69
+ const recoveredAddress = recoverAddress(hash, signature);
70
+
71
+ if (recoveredAddress === ZeroAddress || recoveredAddress !== signerAddress)
72
+ throw new InvalidSignatureError(hash, signerAddress, recoveredAddress);
73
+ }
74
+
75
+ export function getMessage(
76
+ domain: TypedDataDomain,
77
+ types: Record<string, TypedDataField[]>,
78
+ value: Record<string, any>
79
+ ): SignatureMessage {
80
+ const hash = TypedDataEncoder.hash(domain, types, value);
81
+
82
+ return { data: { domain, types, value }, hash };
83
+ }
@@ -0,0 +1,110 @@
1
+ import { ZeroAddress, parseUnits } from "ethers";
2
+
3
+ import { MarketConfig } from "../../market";
4
+
5
+ export const MAINNET_MARKETS = {
6
+ eth_wstEth: new MarketConfig({
7
+ loanToken: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
8
+ collateralToken: "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0",
9
+ oracle: "0x2a01EB9496094dA03c4E364Def50f5aD1280AD72",
10
+ irm: "0x870aC11D48B15DB9a138Cf899d20F13F79Ba00BC",
11
+ lltv: parseUnits("0.945"),
12
+ }),
13
+ eth_rEth: new MarketConfig({
14
+ loanToken: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
15
+ collateralToken: "0xae78736Cd615f374D3085123A210448E74Fc6393",
16
+ oracle: "0x1b4A3F92e5Fffd1d35A98751c9FE4472483579bB",
17
+ irm: "0x870aC11D48B15DB9a138Cf899d20F13F79Ba00BC",
18
+ lltv: parseUnits("0.945"),
19
+ }),
20
+ usdt_wbtc: new MarketConfig({
21
+ loanToken: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
22
+ collateralToken: "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
23
+ oracle: "0x008bF4B1cDA0cc9f0e882E0697f036667652E1ef",
24
+ irm: "0x870aC11D48B15DB9a138Cf899d20F13F79Ba00BC",
25
+ lltv: parseUnits("0.86"),
26
+ }),
27
+ usdt_wstEth: new MarketConfig({
28
+ loanToken: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
29
+ collateralToken: "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0",
30
+ oracle: "0x95DB30fAb9A3754e42423000DF27732CB2396992",
31
+ irm: "0x870aC11D48B15DB9a138Cf899d20F13F79Ba00BC",
32
+ lltv: parseUnits("0.86"),
33
+ }),
34
+
35
+ usdc_wbtc: new MarketConfig({
36
+ // USDC(wBTC, 86%, Chainlink, AdaptiveCurve)
37
+ loanToken: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
38
+ collateralToken: "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
39
+ oracle: "0xDddd770BADd886dF3864029e4B377B5F6a2B6b83",
40
+ irm: "0x870aC11D48B15DB9a138Cf899d20F13F79Ba00BC",
41
+ lltv: parseUnits("0.86"),
42
+ }),
43
+ usdc_wstEth: new MarketConfig({
44
+ // USDC(wstETH, 86%, Chainlink, AdaptiveCurve)
45
+ loanToken: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
46
+ collateralToken: "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0",
47
+ oracle: "0x48F7E36EB6B826B2dF4B2E630B62Cd25e89E40e2",
48
+ irm: "0x870aC11D48B15DB9a138Cf899d20F13F79Ba00BC",
49
+ lltv: parseUnits("0.86"),
50
+ }),
51
+ usdc_sDai: new MarketConfig({
52
+ // USDC(wstETH, 86%, Chainlink, AdaptiveCurve)
53
+ loanToken: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
54
+ collateralToken: "0x83F20F44975D03b1b09e64809B757c47f942BEeA",
55
+ oracle: "0x6CAFE228eC0B0bC2D076577d56D35Fe704318f6d",
56
+ irm: "0x870aC11D48B15DB9a138Cf899d20F13F79Ba00BC",
57
+ lltv: parseUnits("0.965"),
58
+ }),
59
+ idle_usdc: new MarketConfig({
60
+ loanToken: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
61
+ collateralToken: ZeroAddress,
62
+ oracle: ZeroAddress,
63
+ irm: ZeroAddress,
64
+ lltv: 0n,
65
+ }),
66
+
67
+ crvUsd_stkcvxcrvUSDTWBTCWETH: new MarketConfig({
68
+ collateralToken: "0xb0Ce26C88e4e7DCa51968b6047f44646f5064278",
69
+ irm: "0x870aC11D48B15DB9a138Cf899d20F13F79Ba00BC",
70
+ lltv: parseUnits("0.86"),
71
+ loanToken: "0xf939E0A03FB07F59A73314E73794Be0E57ac1b4E",
72
+ oracle: "0x077Af6c2D4A75D4145d141F9e9421864C3940CB3",
73
+ }),
74
+ crvUsd_stkcvxcrvUSDCWBTCWETH: new MarketConfig({
75
+ collateralToken: "0x0ea1a65A2c255f24Ee8D81eA6AaC54Decd9d269e",
76
+ irm: "0x870aC11D48B15DB9a138Cf899d20F13F79Ba00BC",
77
+ lltv: parseUnits("0.86"),
78
+ loanToken: "0xf939E0A03FB07F59A73314E73794Be0E57ac1b4E",
79
+ oracle: "0xd2F7C3B2fC97cC7b6AfDd76D163394680EFc35b9",
80
+ }),
81
+ crvUsd_stkcvxcrvCRVUSDTBTCWSTETH: new MarketConfig({
82
+ collateralToken: "0x3ce8Ec9f3d89aD0A2DdbCC3FDB8991BD241Fc82E",
83
+ irm: "0x870aC11D48B15DB9a138Cf899d20F13F79Ba00BC",
84
+ lltv: parseUnits("0.86"),
85
+ loanToken: "0xf939E0A03FB07F59A73314E73794Be0E57ac1b4E",
86
+ oracle: "0xa9f7900476F43C45Ebf56cEa669B9c960C176112",
87
+ }),
88
+ crvUsd_stkcvxTryLSD: new MarketConfig({
89
+ collateralToken: "0x6BA072F0d22806F2C52e9792AF47f2D59103BEBE",
90
+ irm: "0x870aC11D48B15DB9a138Cf899d20F13F79Ba00BC",
91
+ lltv: parseUnits("0.86"),
92
+ loanToken: "0xf939E0A03FB07F59A73314E73794Be0E57ac1b4E",
93
+ oracle: "0x18B0d7311a97c5377445C80c768ab5201Bb27B5a",
94
+ }),
95
+ crvUsd_stkcvxcrvUSDETHCRV: new MarketConfig({
96
+ collateralToken: "0xAc904BAfBb5FB04Deb2b6198FdCEedE75a78Ce5a",
97
+ irm: "0x870aC11D48B15DB9a138Cf899d20F13F79Ba00BC",
98
+ lltv: parseUnits("0.86"),
99
+ loanToken: "0xf939E0A03FB07F59A73314E73794Be0E57ac1b4E",
100
+ oracle: "0xad7e157815df05029125B568E39d5402550d60bb",
101
+ }),
102
+
103
+ usda_re7Eth: new MarketConfig({
104
+ collateralToken: "0x78Fc2c2eD1A4cDb5402365934aE5648aDAd094d0",
105
+ irm: "0x870aC11D48B15DB9a138Cf899d20F13F79Ba00BC",
106
+ lltv: parseUnits("0.86"),
107
+ loanToken: "0x0000206329b97DB379d5E1Bf586BbDB969C63274",
108
+ oracle: "0x76052A2A28fDCB8124f4686C63C68355b142de3B",
109
+ }),
110
+ };
@@ -0,0 +1,124 @@
1
+ import {
2
+ Contract,
3
+ ContractRunner,
4
+ Interface,
5
+ decodeBytes32String,
6
+ isHexString,
7
+ } from "ethers";
8
+ import { ERC20__factory } from "ethers-types";
9
+ import { ERC20, ERC20Interface } from "ethers-types/dist/token/ERC20/ERC20";
10
+
11
+ import addresses from "@morpho-org/blue-sdk/src/addresses";
12
+
13
+ import { ChainId } from "../chain";
14
+
15
+ export const isBytes32ERC20Metadata = (address: string, chainId: ChainId) => {
16
+ switch (chainId) {
17
+ case ChainId.EthMainnet:
18
+ return [addresses[ChainId.EthMainnet].mkr].includes(address);
19
+ default:
20
+ return false;
21
+ }
22
+ };
23
+
24
+ export const decodeString = (bytes32OrStr: string) => {
25
+ if (isHexString(bytes32OrStr, 32)) return decodeBytes32String(bytes32OrStr);
26
+
27
+ return bytes32OrStr;
28
+ };
29
+
30
+ const _bytes32ERC20Abi = [
31
+ ...ERC20__factory.abi.filter(
32
+ (fragment) =>
33
+ !("name" in fragment) ||
34
+ (fragment.name !== "name" && fragment.name !== "symbol")
35
+ ),
36
+ {
37
+ inputs: [],
38
+ name: "symbol",
39
+ outputs: [
40
+ {
41
+ name: "symbol",
42
+ type: "bytes32",
43
+ },
44
+ ],
45
+ stateMutability: "view",
46
+ type: "function",
47
+ },
48
+
49
+ {
50
+ inputs: [],
51
+ name: "name",
52
+ outputs: [
53
+ {
54
+ name: "name",
55
+ type: "bytes32",
56
+ },
57
+ ],
58
+ stateMutability: "view",
59
+ type: "function",
60
+ },
61
+ ] as const;
62
+
63
+ export class Bytes32ERC20__factory {
64
+ static readonly abi = _bytes32ERC20Abi;
65
+
66
+ static createInterface() {
67
+ return new Interface(_bytes32ERC20Abi) as ERC20Interface;
68
+ }
69
+ static connect(address: string, runner?: ContractRunner | null) {
70
+ const erc20 = new Contract(
71
+ address,
72
+ _bytes32ERC20Abi,
73
+ runner
74
+ ) as unknown as ERC20;
75
+
76
+ const name = erc20.name.bind(erc20);
77
+ erc20.name = Object.assign(
78
+ (...args: Parameters<typeof name>) => name(...args).then(decodeString),
79
+ name
80
+ );
81
+
82
+ const symbol = erc20.symbol.bind(erc20);
83
+ erc20.symbol = Object.assign(
84
+ (...args: Parameters<typeof symbol>) =>
85
+ symbol(...args).then(decodeString),
86
+ symbol
87
+ );
88
+
89
+ return erc20;
90
+ }
91
+ }
92
+
93
+ export class ERC20Metadata__factory {
94
+ static connect(
95
+ address: string,
96
+ chainId: ChainId,
97
+ runner?: ContractRunner | null
98
+ ) {
99
+ if (isBytes32ERC20Metadata(address, chainId))
100
+ return Bytes32ERC20__factory.connect(address, runner);
101
+
102
+ const erc20 = ERC20__factory.connect(address, runner);
103
+
104
+ const name = erc20.name.bind(erc20);
105
+ erc20.name = Object.assign(
106
+ (...args: Parameters<typeof name>) =>
107
+ name(...args).catch(() =>
108
+ Bytes32ERC20__factory.connect(address, runner).name(...args)
109
+ ),
110
+ name
111
+ );
112
+
113
+ const symbol = erc20.symbol.bind(erc20);
114
+ erc20.symbol = Object.assign(
115
+ (...args: Parameters<typeof symbol>) =>
116
+ symbol(...args).catch(() =>
117
+ Bytes32ERC20__factory.connect(address, runner).symbol(...args)
118
+ ),
119
+ symbol
120
+ );
121
+
122
+ return erc20;
123
+ }
124
+ }