@morpho-org/blue-sdk 1.0.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/README.md +98 -0
- package/package.json +54 -0
- package/src/addresses.ts +261 -0
- package/src/chain/chain.constants.ts +235 -0
- package/src/chain/chain.test.ts +51 -0
- package/src/chain/chain.types.ts +42 -0
- package/src/chain/chain.utils.ts +44 -0
- package/src/chain/index.ts +2 -0
- package/src/constants.ts +18 -0
- package/src/errors.ts +75 -0
- package/src/ethers/ethers.test.ts +17 -0
- package/src/ethers/index.ts +2 -0
- package/src/ethers/safeGetAddress.ts +4 -0
- package/src/ethers/safeParseUnits.ts +29 -0
- package/src/evm.ts +172 -0
- package/src/helpers/format/format.test.ts +340 -0
- package/src/helpers/format/format.ts +416 -0
- package/src/helpers/format/index.ts +1 -0
- package/src/helpers/getChecksumedAddress.ts +15 -0
- package/src/helpers/index.ts +4 -0
- package/src/helpers/isZeroAddressOrUnset.ts +13 -0
- package/src/helpers/locale.ts +108 -0
- package/src/holding/Holding.ts +109 -0
- package/src/holding/index.ts +1 -0
- package/src/index.ts +34 -0
- package/src/market/Market.ts +479 -0
- package/src/market/MarketConfig.ts +108 -0
- package/src/market/MarketUtils.test.ts +25 -0
- package/src/market/MarketUtils.ts +467 -0
- package/src/market/index.ts +3 -0
- package/src/maths/AdaptiveCurveIrmLib.ts +143 -0
- package/src/maths/MathLib.ts +208 -0
- package/src/maths/MathUtils.ts +31 -0
- package/src/maths/SharesMath.ts +40 -0
- package/src/maths/index.ts +4 -0
- package/src/notifications.ts +167 -0
- package/src/position/Position.ts +251 -0
- package/src/position/index.ts +1 -0
- package/src/signatures/index.ts +18 -0
- package/src/signatures/manager.ts +50 -0
- package/src/signatures/permit.ts +126 -0
- package/src/signatures/permit2.ts +120 -0
- package/src/signatures/types.ts +18 -0
- package/src/signatures/utils.ts +83 -0
- package/src/tests/mocks/markets.ts +110 -0
- package/src/token/ERC20Metadata.ts +124 -0
- package/src/token/Token.ts +83 -0
- package/src/token/TokenNamespace.ts +76 -0
- package/src/token/WrappedToken.ts +142 -0
- package/src/token/index.ts +2 -0
- package/src/types.ts +37 -0
- package/src/user/User.ts +32 -0
- package/src/user/index.ts +2 -0
- package/src/user/user.types.ts +23 -0
- package/src/vault/Vault.ts +370 -0
- package/src/vault/VaultAllocation.ts +58 -0
- package/src/vault/VaultConfig.ts +55 -0
- package/src/vault/VaultUtils.ts +47 -0
- package/src/vault/index.ts +4 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as _Manager from "./manager";
|
|
2
|
+
import * as _Permit from "./permit";
|
|
3
|
+
import * as _Permit2 from "./permit2";
|
|
4
|
+
import {
|
|
5
|
+
safeSignTypedData as _safeSignTypedData,
|
|
6
|
+
verifySignature as _verifySignature,
|
|
7
|
+
getMessage as _getMessage,
|
|
8
|
+
} from "./utils";
|
|
9
|
+
|
|
10
|
+
export namespace SignatureUtils {
|
|
11
|
+
export import Permit = _Permit;
|
|
12
|
+
export import Permit2 = _Permit2;
|
|
13
|
+
export import Manager = _Manager;
|
|
14
|
+
|
|
15
|
+
export const safeSignTypedData = _safeSignTypedData;
|
|
16
|
+
export const verifySignature = _verifySignature;
|
|
17
|
+
export const getMessage = _getMessage;
|
|
18
|
+
}
|
|
@@ -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
|
+
}
|