import { JsonFragment, LogDescription } from "@ethersproject/abi"; import { BigNumber } from "@ethersproject/bignumber"; import { Log } from "@ethersproject/abstract-provider"; import { Contract, ContractInterface, ContractFunction, Overrides, CallOverrides, PopulatedTransaction, ContractTransaction } from "@ethersproject/contracts"; import activePoolAbi from "../abi/ActivePool.json"; import borrowerOperationsAbi from "../abi/BorrowerOperations.json"; import collSurplusPoolAbi from "../abi/CollSurplusPool.json"; import communityIssuanceAbi from "../abi/CommunityIssuance.json"; import defaultPoolAbi from "../abi/DefaultPool.json"; import erc20Abi from "../abi/IERC20.json"; import gasPoolAbi from "../abi/GasPool.json"; import hintHelpersAbi from "../abi/HintHelpers.json"; import arthTokenAbi from "../abi/ARTHValuecoin.json"; import multiTroveGetterAbi from "../abi/MultiTroveGetter.json"; import priceFeedAbi from "../abi/PriceFeed.json"; import priceFeedTestnetAbi from "../abi/PriceFeedTestnet.json"; import sortedTrovesAbi from "../abi/SortedTroves.json"; import stabilityPoolAbi from "../abi/StabilityPool.json"; import troveManagerAbi from "../abi/TroveManager.json"; import governanceAbi from "../abi/Governance.json"; import { ActivePool, BorrowerOperations, TroveManager, ARTHValuecoin, CollSurplusPool, CommunityIssuance, MockERC20, DefaultPool, HintHelpers, MultiTroveGetter, PriceFeed, PriceFeedTestnet, SortedTroves, StabilityPool, GasPool, Governance } from "../types"; import { EthersProvider, EthersSigner } from "./types"; export interface _TypedLogDescription extends Omit { args: T; } type BucketOfFunctions = Record never>; // Removes unsafe index signatures from an Ethers contract type export type _TypeSafeContract = Pick< T, { [P in keyof T]: BucketOfFunctions extends T[P] ? never : P; } extends { [_ in keyof T]: infer U; } ? U : never >; type EstimatedContractFunction = ( overrides: O, adjustGas: (gas: BigNumber) => BigNumber, ...args: A ) => Promise; type CallOverridesArg = [overrides?: CallOverrides]; type TypedContract = _TypeSafeContract & U & { [P in keyof V]: V[P] extends (...args: infer A) => unknown ? (...args: A) => Promise : never; } & { readonly callStatic: { [P in keyof V]: V[P] extends (...args: [...infer A, never]) => infer R ? (...args: [...A, ...CallOverridesArg]) => R : never; }; readonly estimateGas: { [P in keyof V]: V[P] extends (...args: infer A) => unknown ? (...args: A) => Promise : never; }; readonly populateTransaction: { [P in keyof V]: V[P] extends (...args: infer A) => unknown ? (...args: A) => Promise : never; }; readonly estimateAndPopulate: { [P in keyof V]: V[P] extends (...args: [...infer A, infer O | undefined]) => unknown ? EstimatedContractFunction : never; }; }; const buildEstimatedFunctions = ( estimateFunctions: Record>, functions: Record> ): Record> => Object.fromEntries( Object.keys(estimateFunctions).map(functionName => [ functionName, async (overrides, adjustEstimate, ...args) => { if (overrides.gasLimit === undefined) { const estimatedGas = await estimateFunctions[functionName](...args, overrides); overrides = { ...overrides, gasLimit: adjustEstimate(estimatedGas) }; } return functions[functionName](...args, overrides); } ]) ); export class _ARTHContract extends Contract { readonly estimateAndPopulate: Record>; constructor( addressOrName: string, contractInterface: ContractInterface, signerOrProvider?: EthersSigner | EthersProvider ) { super(addressOrName, contractInterface, signerOrProvider); // this.estimateAndCall = buildEstimatedFunctions(this.estimateGas, this); this.estimateAndPopulate = buildEstimatedFunctions(this.estimateGas, this.populateTransaction); } extractEvents(logs: Log[], name: string): _TypedLogDescription[] { return logs .filter(log => log.address === this.address) .map(log => this.interface.parseLog(log)) .filter(e => e.name === name); } } /** @internal */ export type _TypedARTHContract = TypedContract<_ARTHContract, T, U>; /** @internal */ export interface _ARTHContracts { activePool: ActivePool; borrowerOperations: BorrowerOperations; troveManager: TroveManager; arthToken: ARTHValuecoin; mahaToken: MockERC20; collSurplusPool: CollSurplusPool; communityIssuance: CommunityIssuance; defaultPool: DefaultPool; hintHelpers: HintHelpers; multiTroveGetter: MultiTroveGetter; priceFeed: PriceFeed | PriceFeedTestnet; sortedTroves: SortedTroves; stabilityPool: StabilityPool; gasPool: GasPool; governance: Governance } /** @internal */ export const _priceFeedIsTestnet = ( priceFeed: PriceFeed | PriceFeedTestnet ): priceFeed is PriceFeedTestnet => "setPrice" in priceFeed; type ARTHContractsKey = keyof _ARTHContracts; /** @internal */ export type _ARTHContractAddresses = Record; type ARTHContractAbis = Record; const getAbi = (priceFeedIsTestnet: boolean): ARTHContractAbis => ({ activePool: activePoolAbi, borrowerOperations: borrowerOperationsAbi, troveManager: troveManagerAbi, arthToken: arthTokenAbi, collSurplusPool: collSurplusPoolAbi, mahaToken: erc20Abi, communityIssuance: communityIssuanceAbi, defaultPool: defaultPoolAbi, hintHelpers: hintHelpersAbi, multiTroveGetter: multiTroveGetterAbi, priceFeed: priceFeedIsTestnet ? priceFeedTestnetAbi : priceFeedAbi, sortedTroves: sortedTrovesAbi, stabilityPool: stabilityPoolAbi, gasPool: gasPoolAbi, governance: governanceAbi }); const mapARTHContracts = ( contracts: Record, f: (t: T, key: ARTHContractsKey) => U ) => Object.fromEntries( Object.entries(contracts).map(([key, t]) => [key, f(t, key as ARTHContractsKey)]) ) as Record; /** @internal */ export interface _ARTHDeploymentJSON { readonly chainId: number; readonly addresses: _ARTHContractAddresses; readonly version: string; readonly deploymentDate: number; readonly startBlock: number; readonly bootstrapPeriod: number; readonly totalStabilityPoolMAHAReward: string; readonly _priceFeedIsTestnet: boolean; readonly _isDev: boolean; } /** @internal */ export const _connectToContracts = ( signerOrProvider: EthersSigner | EthersProvider, { addresses, _priceFeedIsTestnet }: _ARTHDeploymentJSON ): _ARTHContracts => { const abi = getAbi(_priceFeedIsTestnet); return mapARTHContracts( addresses, (address, key) => new _ARTHContract(address, abi[key], signerOrProvider) as _TypedARTHContract ) as _ARTHContracts; };