@moonwell-fi/moonwell-sdk
Version:
TypeScript Interface for Moonwell
642 lines (617 loc) • 17.1 kB
text/typescript
import {
type Abi,
type Address,
type Chain,
type ChainContract,
type Hex,
type Narrow,
type Prettify,
type PublicClient,
type Transport,
createPublicClient,
getContract,
} from "viem";
import {
ChainLinkOracleAbi,
ComptrollerTokenAbi,
CoreRouterAbi,
CoreViewsAbi,
GovernanceTokenAbi,
GovernorAbi,
MarketTokenAbi,
MaximillionAbi,
MorphoBlueAbi,
MorphoBundlerAbi,
MorphoPublicAllocatorAbi,
MorphoVaultAbi,
MorphoViewsAbi,
MultiRewardDistributorAbi,
MultichainGovernorAbi,
StakingTokenAbi,
TemporalGovernorAbi,
TokenAbi,
VoteCollectorAbi,
WrappedNativeTokenAbi,
} from "../abis/index.js";
import type { GovernanceToken } from "../definitions/governance.js";
import type {
ChainLinkOracleContractReturnType,
ComptrollerContractReturnType,
CoreRouterContractReturnType,
CoreViewsContractReturnType,
GovernanceTokenContractReturnType,
GovernorContractReturnType,
MarketTokenContractReturnType,
MaximillionContractReturnType,
MorphoBlueContractReturnType,
MorphoBundlerContractReturnType,
MorphoPublicAllocatorContractReturnType,
MorphoVaultContractReturnType,
MorphoViewsContractReturnType,
MultiRewardDistributorContractReturnType,
MultichainGovernorContractReturnType,
StakingTokenContractReturnType,
TemporalGovernorContractReturnType,
TokenContractReturnType,
TokenSaleContractReturnType,
VoteCollectorContractReturnType,
WrappedNativeTokenContractReturnType,
} from "./contracts.js";
export type TokenConfig = {
address: `0x${string}`;
decimals: number;
name: string;
symbol: string;
};
export type VaultConfig<tokens> = {
vaultToken: keyof tokens;
underlyingToken: keyof tokens;
multiReward?: Address;
};
export type MarketConfig<tokens> = {
marketToken: keyof tokens;
underlyingToken: keyof tokens;
deprecated?: boolean;
badDebt?: boolean;
};
export type MorphoMarketConfig<tokens> = {
collateralToken: keyof tokens;
loanToken: keyof tokens;
id: Hex;
deprecated?: boolean;
};
export type ContractConfig<tokens> = {
stakingToken?: keyof tokens;
governanceToken?: keyof tokens;
wrappedNativeToken?: keyof tokens;
comptroller?: Address;
maximillion?: Address;
views?: Address;
tokenSale?: Address;
morphoViews?: Address;
multiRewardDistributor?: Address;
temporalGovernor?: Address;
voteCollector?: Address;
governor?: Address;
multichainGovernor?: Address;
oracle?: Address;
router?: Address;
morphoBlue?: Address;
morphoBaseBundler?: Address;
morphoBundler?: Address;
morphoPublicAllocator?: Address;
};
export type ContractsConfigReturnType = {
stakingToken: TokenContractReturnType;
governanceToken: TokenContractReturnType;
wrappedNativeToken: TokenContractReturnType;
comptroller: ComptrollerContractReturnType;
maximillion: MaximillionContractReturnType;
views: CoreViewsContractReturnType;
tokenSale: TokenSaleContractReturnType;
morphoViews: MorphoViewsContractReturnType;
multiRewardDistributor: MultiRewardDistributorContractReturnType;
temporalGovernor: TemporalGovernorContractReturnType;
voteCollector: VoteCollectorContractReturnType;
governor: GovernorContractReturnType;
multichainGovernor: MultichainGovernorContractReturnType;
oracle: ChainLinkOracleContractReturnType;
router: CoreRouterContractReturnType;
morphoBlue: MorphoBlueContractReturnType;
morphoBaseBundler: MorphoBundlerContractReturnType;
morphoBundler: MorphoBundlerContractReturnType;
morphoPublicAllocator: MorphoPublicAllocatorContractReturnType;
};
export type CustomConfigType = {
morpho?: {
minimalDeployment?: boolean;
subgraphUrl?: string;
};
governance?: {
token: GovernanceToken;
chainIds: number[];
proposalIdOffset?: number;
snapshotEnsName?: string;
};
multiRewarder?: {
rewardToken: string;
}[];
wormhole?: {
chainId: number;
tokenBridge?: ChainContract | undefined;
};
socket?: {
gateway?: ChainContract | undefined;
};
xWELL?: {
bridgeAdapter?: ChainContract | undefined;
};
};
export type GetContractConfig<tokens, contract> = contract extends {}
? contract
: keyof tokens;
export type TokensConfig<tokens> = {} extends tokens
? {}
: { [tokenName in keyof tokens]: TokenConfig };
export type VaultsConfig<vaults, tokens> = {} extends vaults
? {}
: { [name in keyof tokens]?: VaultConfig<tokens> };
export type MarketsConfig<markets, tokens> = {} extends markets
? {}
: { [name in keyof tokens]?: MarketConfig<tokens> };
export type MorphoMarketsConfig<markets, tokens> = {} extends markets
? {}
: { [name in keyof markets]: MorphoMarketConfig<tokens> };
export type ContractsConfig<contracts, tokens> = {} extends contracts
? {}
: { [name in keyof ContractConfig<tokens>]?: ContractConfig<tokens>[name] };
export type CustomConfig<custom> = {} extends custom
? {}
: { [name in keyof CustomConfigType]?: CustomConfigType[name] };
export const createTokenConfig = <const tokens>(
tokens: TokensConfig<Narrow<tokens>>,
) => tokens as Prettify<tokens>;
export const createVaultConfig = <const tokens, const vaults>(config: {
tokens: TokensConfig<tokens>;
vaults: VaultsConfig<vaults, tokens>;
}) => config.vaults as Prettify<vaults>;
export const createMarketConfig = <const tokens, const markets>(config: {
tokens: TokensConfig<tokens>;
markets: MarketsConfig<markets, tokens>;
}) => config.markets as Prettify<markets>;
export const createMorphoMarketConfig = <const tokens, const markets>(config: {
tokens: TokensConfig<tokens>;
markets: MorphoMarketsConfig<markets, tokens>;
}) => config.markets as Prettify<markets>;
export const createContractsConfig = <const tokens, const contracts>(config: {
tokens: TokensConfig<tokens>;
contracts: ContractsConfig<contracts, tokens>;
}) => {
return config.contracts as Prettify<contracts>;
};
export const createCustomConfig = <custom>(custom: CustomConfig<custom>) => {
return custom as Prettify<custom>;
};
export const createEnvironmentConfig = <
tokens,
markets,
vaults,
morphoMarkets,
contracts,
custom,
>(config: {
key: string;
name: string;
chain: Chain;
transport: Transport;
indexerUrl: string;
governanceIndexerUrl: string;
tokens: TokensConfig<tokens>;
markets: MarketsConfig<markets, tokens>;
vaults: VaultsConfig<vaults, tokens>;
morphoMarkets: MorphoMarketsConfig<morphoMarkets, tokens>;
contracts: ContractsConfig<contracts, tokens>;
custom: CustomConfig<custom>;
}) => {
const publicClient = createPublicClient({
chain: config.chain,
batch: {
multicall: {
wait: 100,
},
},
cacheTime: 5_000,
transport: config.transport,
});
const createContract = <const abi extends Abi>(
address: Address,
abi: abi,
) => {
return getContract({
address,
abi,
client: publicClient,
});
};
const getTokenContract = <const abi extends Abi>(
key: keyof tokens | undefined,
abi: abi,
) => {
if (key) {
const token = config.tokens[key] as TokenConfig;
return getContract({
address: token.address,
abi,
client: publicClient,
});
} else {
return undefined;
}
};
const tokenContracts = Object.keys(config.tokens).reduce(
(prev, curr: string) => {
return {
...prev,
[]: getTokenContract(curr as keyof tokens, TokenAbi),
};
},
{},
) as {
[]: TokenContractReturnType;
};
const marketContracts = Object.keys(config.markets).reduce((prev, curr) => {
const market = (config.markets as any)[curr] as MarketConfig<tokens>;
return {
...prev,
[]: getTokenContract(market.marketToken, MarketTokenAbi),
};
}, {}) as {
[]: MarketTokenContractReturnType;
};
const vaultsContracts = Object.keys(config.vaults || {}).reduce(
(prev, curr: string) => {
return {
...prev,
[]: getTokenContract(curr as keyof tokens, MorphoVaultAbi),
};
},
{},
) as {
[]: MorphoVaultContractReturnType;
};
const contracts = Object.keys(config.contracts).reduce((prev, curr) => {
const key = curr as keyof ContractConfig<any>;
let contractAddress = (config.contracts as any)[key] as Address;
let abi: Abi = TokenAbi;
switch (key) {
case "comptroller":
abi = ComptrollerTokenAbi;
break;
case "maximillion":
abi = MaximillionAbi;
break;
case "views":
abi = CoreViewsAbi;
break;
case "morphoViews":
abi = MorphoViewsAbi;
break;
case "multiRewardDistributor":
abi = MultiRewardDistributorAbi;
break;
case "temporalGovernor":
abi = TemporalGovernorAbi;
break;
case "voteCollector":
abi = VoteCollectorAbi;
break;
case "governor":
abi = GovernorAbi;
break;
case "multichainGovernor":
abi = MultichainGovernorAbi;
break;
case "oracle":
abi = ChainLinkOracleAbi;
break;
case "router":
abi = CoreRouterAbi;
break;
case "morphoBlue":
abi = MorphoBlueAbi;
break;
case "morphoBundler":
abi = MorphoBundlerAbi;
break;
case "morphoPublicAllocator":
abi = MorphoPublicAllocatorAbi;
break;
case "stakingToken":
contractAddress = (
(config.tokens as any)[contractAddress] as TokenConfig
).address;
abi = StakingTokenAbi;
break;
case "governanceToken":
contractAddress = (
(config.tokens as any)[contractAddress] as TokenConfig
).address;
abi = GovernanceTokenAbi;
break;
case "wrappedNativeToken":
contractAddress = (
(config.tokens as any)[contractAddress] as TokenConfig
).address;
abi = WrappedNativeTokenAbi;
break;
}
return {
...prev,
[]: createContract(contractAddress, abi),
};
}, {}) as Prettify<
{
[]: StakingTokenContractReturnType;
} & {
[]: WrappedNativeTokenContractReturnType;
} & {
[]: GovernanceTokenContractReturnType;
} & {
[]: ComptrollerContractReturnType;
} & {
[]: MaximillionContractReturnType;
} & {
[]: CoreViewsContractReturnType;
} & {
[]: TokenSaleContractReturnType;
} & {
[]: MorphoViewsContractReturnType;
} & {
[]: MultiRewardDistributorContractReturnType;
} & {
[]: TemporalGovernorContractReturnType;
} & {
[]: VoteCollectorContractReturnType;
} & {
[]: GovernorContractReturnType;
} & {
[]: MultichainGovernorContractReturnType;
} & {
[]: ChainLinkOracleContractReturnType;
} & {
[]: CoreRouterContractReturnType;
} & {
[]: MorphoBlueContractReturnType;
} & {
[]: MorphoBundlerContractReturnType;
} & {
[]: MorphoBundlerContractReturnType;
} & {
[]: MorphoPublicAllocatorContractReturnType;
}
>;
return {
key: config.key,
name: config.name,
chainId: config.chain.id,
chain: config.chain,
indexerUrl: config.indexerUrl,
governanceIndexerUrl: config.governanceIndexerUrl,
tokens: tokenContracts,
markets: marketContracts,
vaults: vaultsContracts,
contracts: contracts,
custom: config.custom as custom,
config: {
tokens: config.tokens as {
[]: TokenConfig;
},
vaults: config.vaults as {
[]: VaultConfig<tokens>;
},
markets: config.markets as {
[]: MarketConfig<tokens>;
},
morphoMarkets: config.morphoMarkets as {
[]: MorphoMarketConfig<tokens>;
},
contracts: config.contracts,
},
publicClient,
} as Environment<tokens, markets, vaults, contracts, custom>;
};
export type Environment<
tokens = any,
markets = any,
vaults = any,
contracts = Partial<ContractsConfigReturnType>,
custom = CustomConfigType,
> = {
key: string;
name: string;
chainId: number;
chain: Chain;
indexerUrl: string;
governanceIndexerUrl: string;
tokens: {
[]: TokenContractReturnType;
};
markets: {
[]: MarketTokenContractReturnType;
};
vaults: {
[]: MorphoVaultContractReturnType;
};
contracts: Prettify<
{
[]: StakingTokenContractReturnType;
} & {
[]: WrappedNativeTokenContractReturnType;
} & {
[]: GovernanceTokenContractReturnType;
} & {
[]: ComptrollerContractReturnType;
} & {
[]: MaximillionContractReturnType;
} & {
[]: CoreViewsContractReturnType;
} & {
[]: TokenSaleContractReturnType;
} & {
[]: MorphoViewsContractReturnType;
} & {
[]: MultiRewardDistributorContractReturnType;
} & {
[]: TemporalGovernorContractReturnType;
} & {
[]: VoteCollectorContractReturnType;
} & {
[]: GovernorContractReturnType;
} & {
[]: MultichainGovernorContractReturnType;
} & {
[]: ChainLinkOracleContractReturnType;
} & {
[]: CoreRouterContractReturnType;
} & {
[]: MorphoBlueContractReturnType;
} & {
[]: MorphoBundlerContractReturnType;
} & {
[]: MorphoBundlerContractReturnType;
} & {
[]: MorphoPublicAllocatorContractReturnType;
}
>;
custom: custom;
config: {
tokens: {
[]: TokenConfig;
};
markets: {
[]: MarketConfig<Record<string, any>>;
};
vaults: {
[]: VaultConfig<Record<string, any>>;
};
morphoMarkets: {
[]: MorphoMarketConfig<Record<string, any>>;
};
contracts: ContractConfig<Record<string, any>>;
};
publicClient: PublicClient;
};